1 /* $NetBSD: u3g.c,v 1.8 2009/11/12 19:52:14 dyoung Exp $ */
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
32 * Copyright (c) 2008 AnyWi Technologies
33 * Author: Andrea Guzzo <aguzzo@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 *
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.
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.
52 #include <sys/cdefs.h>
53 __KERNEL_RCSID(0, "$NetBSD: u3g.c,v 1.8 2009/11/12 19:52:14 dyoung Exp $");
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/kernel.h>
58 #include <sys/malloc.h>
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>
68 #include <dev/usb/ucomvar.h>
73 * We read/write data from/to the device in 4KB chunks to maximise
76 #define U3G_BUFF_SIZE 4096
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.
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
89 * All this happens before the application gets a chance to disable ECHO.
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.
95 #define U3G_PURGE_SECS 2
98 * Define bits for the virtual modem control pins.
99 * The input pin states are reported via the interrupt pipe on some devices.
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)
108 * USB request to set the output pin status
110 #define U3G_SET_PIN 0x22
114 usbd_device_handle sc_udev
;
115 bool sc_dying
; /* We're going away */
117 device_t sc_ucom
; /* Child ucom(4) handle */
118 int sc_ifaceno
; /* Device interface number */
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 */
124 u_char sc_msr
; /* Emulated 'msr' */
125 uint16_t sc_outpins
; /* Output pin state */
127 usbd_pipe_handle sc_intr_pipe
; /* Interrupt pipe */
128 u_char
*sc_intr_buff
; /* Interrupt buffer */
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.
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.
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);
146 CFATTACH_DECL2_NEW(u3ginit
, 0, u3ginit_match
,
147 u3ginit_attach
, u3ginit_detach
, NULL
, NULL
, NULL
);
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
);
156 CFATTACH_DECL2_NEW(u3g
, sizeof(struct u3g_softc
), u3g_match
,
157 u3g_attach
, u3g_detach
, u3g_activate
, NULL
, u3g_childdet
);
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
*);
168 struct ucom_methods u3g_methods
= {
180 * Allegedly supported devices
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
},
190 { USB_VENDOR_HUAWEI
, USB_PRODUCT_HUAWEI_MOBILE
},
191 { USB_VENDOR_HUAWEI
, USB_PRODUCT_HUAWEI_E220
},
193 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_MERLINV620
},
194 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_ES620
},
195 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_MC950D
},
196 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_U720
},
197 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_U727
},
198 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_MERLINU740
},
199 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_U740_2
},
200 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_U870
},
201 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_MERLINV620
},
202 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_S720
},
203 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_V740
},
204 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_X950D
},
205 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_XU870
},
206 { USB_VENDOR_DELL
, USB_PRODUCT_DELL_W5500
},
208 { USB_VENDOR_NOVATEL2
, USB_PRODUCT_NOVATEL2_MC950D_DRIVER
},
211 { USB_VENDOR_MERLIN
, USB_PRODUCT_MERLIN_V620
},
213 /* OEM: Sierra Wireless: */
214 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AIRCARD580
},
215 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AIRCARD595
},
216 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AC595U
},
217 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AC597E
},
218 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_C597
},
219 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AC880
},
220 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AC880E
},
221 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AC880U
},
222 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AC881
},
223 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AC881E
},
224 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AC881U
},
225 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_EM5625
},
226 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MC5720
},
227 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MC5720_2
},
228 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MC5725
},
229 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MINI5725
},
230 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AIRCARD875
},
231 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MC8755
},
232 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MC8755_2
},
233 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MC8755_3
},
234 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MC8765
},
235 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_AC875U
},
236 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MC8775_2
},
237 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MC8780
},
238 { USB_VENDOR_SIERRA
, USB_PRODUCT_SIERRA_MC8781
},
242 u3g_novatel_reinit(usbd_device_handle dev
)
244 unsigned char cmd
[31];
245 usbd_interface_handle iface
;
246 usb_interface_descriptor_t
*id
;
247 usb_endpoint_descriptor_t
*ed
;
248 usbd_pipe_handle pipe
;
249 usbd_xfer_handle xfer
;
252 memset(cmd
, 0, sizeof(cmd
));
253 /* Byte 0..3: Command Block Wrapper (CBW) signature */
258 /* 4..7: CBW Tag, has to unique, but only a single transfer used. */
260 /* 8..11: CBW Transfer Length, no data here */
261 /* 12: CBW Flag: output, so 0 */
265 /* Rest is the SCSI payload */
266 /* 0: SCSI START/STOP opcode */
269 /* 4 Load/Eject command */
274 /* Move the device into the configured state. */
275 err
= usbd_set_config_index(dev
, 0, 0);
277 aprint_error("u3g: failed to set configuration index\n");
281 err
= usbd_device2interface_handle(dev
, 0, &iface
);
283 aprint_error("u3g: failed to get interface\n");
287 id
= usbd_get_interface_descriptor(iface
);
289 for (i
= 0 ; i
< id
->bNumEndpoints
; i
++) {
290 ed
= usbd_interface2endpoint_descriptor(iface
, i
);
293 if (UE_GET_DIR(ed
->bEndpointAddress
) != UE_DIR_OUT
)
295 if ((ed
->bmAttributes
& UE_XFERTYPE
) == UE_BULK
)
299 if (i
== id
->bNumEndpoints
)
302 err
= usbd_open_pipe(iface
, ed
->bEndpointAddress
, USBD_EXCLUSIVE_USE
,
305 aprint_error("u3g: failed to open bulk transfer pipe %d\n",
306 ed
->bEndpointAddress
);
310 xfer
= usbd_alloc_xfer(dev
);
312 usbd_setup_xfer(xfer
, pipe
, NULL
, cmd
, sizeof(cmd
),
313 USBD_SYNCHRONOUS
, USBD_DEFAULT_TIMEOUT
, NULL
);
315 err
= usbd_transfer(xfer
);
317 aprint_error("u3g: transfer failed\n");
318 usbd_free_xfer(xfer
);
320 aprint_error("u3g: failed to allocate xfer\n");
324 usbd_abort_pipe(pipe
);
325 usbd_close_pipe(pipe
);
327 return (err
== USBD_NORMAL_COMPLETION
? UMATCH_HIGHEST
: UMATCH_NONE
);
331 u3g_huawei_reinit(usbd_device_handle dev
)
334 * The Huawei device presents itself as a umass device with Windows
335 * drivers on it. After installation of the driver, it reinits into a
338 usb_device_request_t req
;
339 usb_config_descriptor_t
*cdesc
;
341 /* Get the config descriptor */
342 cdesc
= usbd_get_config_descriptor(dev
);
344 usb_device_descriptor_t dd
;
346 if (usbd_get_device_desc(dev
, &dd
) != 0)
347 return (UMATCH_NONE
);
349 if (dd
.bNumConfigurations
!= 1)
350 return (UMATCH_NONE
);
352 if (usbd_set_config_index(dev
, 0, 1) != 0)
353 return (UMATCH_NONE
);
355 cdesc
= usbd_get_config_descriptor(dev
);
358 return (UMATCH_NONE
);
362 * One iface means umass mode, more than 1 (4 usually) means 3G mode.
364 * XXX: We should check the first interface's device class just to be
365 * sure. If it's a mass storage device, then we can be fairly certain
366 * it needs a mode-switch.
368 if (cdesc
->bNumInterface
> 1)
369 return (UMATCH_NONE
);
371 req
.bmRequestType
= UT_WRITE_DEVICE
;
372 req
.bRequest
= UR_SET_FEATURE
;
373 USETW(req
.wValue
, UF_DEVICE_REMOTE_WAKEUP
);
374 USETW(req
.wIndex
, UHF_PORT_SUSPEND
);
375 USETW(req
.wLength
, 0);
377 (void) usbd_do_request(dev
, &req
, 0);
379 return (UMATCH_HIGHEST
); /* Match to prevent umass from attaching */
383 u3g_sierra_reinit(usbd_device_handle dev
)
385 /* Some Sierra devices presents themselves as a umass device with
386 * Windows drivers on it. After installation of the driver, it
387 * reinits into a * 3G serial device.
389 usb_device_request_t req
;
391 req
.bmRequestType
= UT_VENDOR
;
392 req
.bRequest
= UR_SET_INTERFACE
;
393 USETW(req
.wValue
, UF_DEVICE_REMOTE_WAKEUP
);
394 USETW(req
.wIndex
, UHF_PORT_CONNECTION
);
395 USETW(req
.wLength
, 0);
397 (void) usbd_do_request(dev
, &req
, 0);
399 return (UMATCH_HIGHEST
); /* Match to prevent umass from attaching */
406 * Claim the entire device if a mode-switch is required.
410 u3ginit_match(device_t parent
, cfdata_t match
, void *aux
)
412 struct usb_attach_arg
*uaa
= aux
;
414 if (uaa
->vendor
== USB_VENDOR_HUAWEI
)
415 return u3g_huawei_reinit(uaa
->device
);
417 if (uaa
->vendor
== USB_VENDOR_NOVATEL2
&&
418 uaa
->product
== USB_PRODUCT_NOVATEL2_MC950D_DRIVER
)
419 return u3g_novatel_reinit(uaa
->device
);
421 if (uaa
->vendor
== USB_VENDOR_SIERRA
&&
422 uaa
->product
== USB_PRODUCT_SIERRA_INSTALLER
)
423 return u3g_sierra_reinit(uaa
->device
);
429 u3ginit_attach(device_t parent
, device_t self
, void *aux
)
431 struct usb_attach_arg
*uaa
= aux
;
434 aprint_normal(": Switching to 3G mode\n");
436 if (uaa
->vendor
== USB_VENDOR_NOVATEL2
&&
437 uaa
->product
== USB_PRODUCT_NOVATEL2_MC950D_DRIVER
) {
438 /* About to disappear... */
442 /* Move the device into the configured state. */
443 (void) usbd_set_config_index(uaa
->device
, 0, 1);
447 u3ginit_detach(device_t self
, int flags
)
455 * Second personality:
457 * Claim only those interfaces required for 3G modem operation.
461 u3g_match(device_t parent
, cfdata_t match
, void *aux
)
463 struct usbif_attach_arg
*uaa
= aux
;
464 usbd_interface_handle iface
;
465 usb_interface_descriptor_t
*id
;
468 if (!usb_lookup(u3g_devs
, uaa
->vendor
, uaa
->product
))
469 return (UMATCH_NONE
);
471 error
= usbd_device2interface_handle(uaa
->device
, uaa
->ifaceno
, &iface
);
473 printf("u3g_match: failed to get interface, err=%s\n",
475 return (UMATCH_NONE
);
478 id
= usbd_get_interface_descriptor(iface
);
480 printf("u3g_match: failed to get interface descriptor\n");
481 return (UMATCH_NONE
);
485 * 3G modems generally report vendor-specific class
487 * XXX: this may be too generalised.
489 return ((id
->bInterfaceClass
== UICLASS_VENDOR
) ?
490 UMATCH_VENDOR_PRODUCT
: UMATCH_NONE
);
494 u3g_attach(device_t parent
, device_t self
, void *aux
)
496 struct u3g_softc
*sc
= device_private(self
);
497 struct usbif_attach_arg
*uaa
= aux
;
498 usbd_device_handle dev
= uaa
->device
;
499 usbd_interface_handle iface
;
500 usb_interface_descriptor_t
*id
;
501 usb_endpoint_descriptor_t
*ed
;
502 struct ucom_attach_args uca
;
504 int n
, intr_address
, intr_size
;
510 sc
->sc_dying
= false;
513 error
= usbd_device2interface_handle(dev
, uaa
->ifaceno
, &iface
);
515 aprint_error_dev(self
, "failed to get interface, err=%s\n",
520 id
= usbd_get_interface_descriptor(iface
);
522 uca
.info
= "3G Modem";
523 uca
.ibufsize
= U3G_BUFF_SIZE
;
524 uca
.obufsize
= U3G_BUFF_SIZE
;
525 uca
.ibufsizepad
= U3G_BUFF_SIZE
;
526 uca
.portno
= uaa
->ifaceno
;
530 uca
.methods
= &u3g_methods
;
532 uca
.bulkin
= uca
.bulkout
= -1;
535 sc
->sc_msr
= UMSR_DSR
| UMSR_CTS
| UMSR_DCD
;
536 sc
->sc_ifaceno
= uaa
->ifaceno
;
538 sc
->sc_purging
= false;
543 for (n
= 0; n
< id
->bNumEndpoints
; n
++) {
544 ed
= usbd_interface2endpoint_descriptor(iface
, n
);
546 aprint_error_dev(self
, "no endpoint descriptor "
547 "for %d (interface: %d)\n", n
, sc
->sc_ifaceno
);
552 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
553 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_INTERRUPT
) {
554 intr_address
= ed
->bEndpointAddress
;
555 intr_size
= UGETW(ed
->wMaxPacketSize
);
557 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
558 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
559 uca
.bulkin
= ed
->bEndpointAddress
;
561 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_OUT
&&
562 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
563 uca
.bulkout
= ed
->bEndpointAddress
;
567 if (uca
.bulkin
== -1) {
568 aprint_error_dev(self
, "Missing bulk in for interface %d\n",
574 if (uca
.bulkout
== -1) {
575 aprint_error_dev(self
, "Missing bulk out for interface %d\n",
581 sc
->sc_ucom
= config_found_sm_loc(self
, "ucombus",
582 NULL
, &uca
, ucomprint
, ucomsubmatch
);
585 * If the interface has an interrupt pipe, open it immediately so
586 * that we can track input pin state changes regardless of whether
587 * the tty(4) device is open or not.
589 if (intr_address
!= -1) {
590 sc
->sc_intr_buff
= malloc(intr_size
, M_USBDEV
, M_WAITOK
);
591 error
= usbd_open_pipe_intr(iface
, intr_address
,
592 USBD_SHORT_XFER_OK
, &sc
->sc_intr_pipe
, sc
, sc
->sc_intr_buff
,
593 intr_size
, u3g_intr
, 100);
595 aprint_error_dev(self
, "cannot open interrupt pipe "
596 "(addr %d)\n", intr_address
);
600 sc
->sc_intr_pipe
= NULL
;
601 sc
->sc_intr_buff
= NULL
;
604 if (!pmf_device_register(self
, NULL
, NULL
))
605 aprint_error_dev(self
, "couldn't establish power handler\n");
609 u3g_detach(device_t self
, int flags
)
611 struct u3g_softc
*sc
= device_private(self
);
617 pmf_device_deregister(self
);
619 if (sc
->sc_ucom
!= NULL
) {
620 rv
= config_detach(sc
->sc_ucom
, flags
);
622 aprint_verbose_dev(self
, "Can't deallocate "
627 if (sc
->sc_intr_pipe
!= NULL
) {
628 (void) usbd_abort_pipe(sc
->sc_intr_pipe
);
629 (void) usbd_close_pipe(sc
->sc_intr_pipe
);
630 sc
->sc_intr_pipe
= NULL
;
632 if (sc
->sc_intr_buff
!= NULL
) {
633 free(sc
->sc_intr_buff
, M_USBDEV
);
634 sc
->sc_intr_buff
= NULL
;
641 u3g_childdet(device_t self
, device_t child
)
643 struct u3g_softc
*sc
= device_private(self
);
645 if (sc
->sc_ucom
== child
)
650 u3g_activate(device_t self
, enum devact act
)
652 struct u3g_softc
*sc
= device_private(self
);
656 case DVACT_DEACTIVATE
:
657 if (sc
->sc_ucom
!= NULL
&& config_deactivate(sc
->sc_ucom
))
672 u3g_intr(usbd_xfer_handle xfer
, usbd_private_handle priv
, usbd_status status
)
674 struct u3g_softc
*sc
= (struct u3g_softc
*)priv
;
680 if (status
!= USBD_NORMAL_COMPLETION
) {
681 if (status
== USBD_NOT_STARTED
|| status
== USBD_CANCELLED
)
683 usbd_clear_endpoint_stall_async(sc
->sc_intr_pipe
);
687 buf
= sc
->sc_intr_buff
;
688 if (buf
[0] == 0xa1 && buf
[1] == 0x20) {
691 msr
= sc
->sc_msr
& ~(UMSR_DCD
| UMSR_DSR
| UMSR_RI
);
693 if (buf
[8] & U3G_INPIN_DCD
)
696 if (buf
[8] & U3G_INPIN_DSR
)
699 if (buf
[8] & U3G_INPIN_RI
)
702 if (msr
!= sc
->sc_msr
) {
705 ucom_status_change(device_private(sc
->sc_ucom
));
712 u3g_get_status(void *arg
, int portno
, u_char
*lsr
, u_char
*msr
)
714 struct u3g_softc
*sc
= arg
;
717 *lsr
= 0; /* LSR isn't supported */
724 u3g_set(void *arg
, int portno
, int reg
, int onoff
)
726 struct u3g_softc
*sc
= arg
;
727 usb_device_request_t req
;
728 uint16_t mask
, new_state
;
736 mask
= U3G_OUTPIN_DTR
;
739 mask
= U3G_OUTPIN_RTS
;
745 new_state
= sc
->sc_outpins
& ~mask
;
749 if (new_state
== sc
->sc_outpins
)
752 sc
->sc_outpins
= new_state
;
754 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
755 req
.bRequest
= U3G_SET_PIN
;
756 USETW(req
.wValue
, new_state
);
757 USETW(req
.wIndex
, sc
->sc_ifaceno
);
758 USETW(req
.wLength
, 0);
760 err
= usbd_do_request(sc
->sc_udev
, &req
, 0);
761 if (err
== USBD_STALLED
)
762 usbd_clear_endpoint_stall(sc
->sc_udev
->default_pipe
);
767 u3g_open(void *arg
, int portno
)
769 struct u3g_softc
*sc
= arg
;
770 usb_device_request_t req
;
771 usb_endpoint_descriptor_t
*ed
;
772 usb_interface_descriptor_t
*id
;
773 usbd_interface_handle ih
;
780 err
= usbd_device2interface_handle(sc
->sc_udev
, portno
, &ih
);
784 id
= usbd_get_interface_descriptor(ih
);
786 for (i
= 0; i
< id
->bNumEndpoints
; i
++) {
787 ed
= usbd_interface2endpoint_descriptor(ih
, i
);
791 if (UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
792 /* Issue ENDPOINT_HALT request */
793 req
.bmRequestType
= UT_WRITE_ENDPOINT
;
794 req
.bRequest
= UR_CLEAR_FEATURE
;
795 USETW(req
.wValue
, UF_ENDPOINT_HALT
);
796 USETW(req
.wIndex
, ed
->bEndpointAddress
);
797 USETW(req
.wLength
, 0);
798 err
= usbd_do_request(sc
->sc_udev
, &req
, 0);
805 sc
->sc_purging
= true;
806 getmicrotime(&sc
->sc_purge_start
);
813 u3g_close(void *arg
, int portno
)
815 struct u3g_softc
*sc
= arg
;
822 u3g_read(void *arg
, int portno
, u_char
**cpp
, uint32_t *ccp
)
824 struct u3g_softc
*sc
= arg
;
825 struct timeval curr_tv
, diff_tv
;
828 * If we're not purging input data following first open, do nothing.
830 if (sc
->sc_purging
== false)
834 * Otherwise check if the purge timeout has expired
836 getmicrotime(&curr_tv
);
837 timersub(&curr_tv
, &sc
->sc_purge_start
, &diff_tv
);
839 if (diff_tv
.tv_sec
>= U3G_PURGE_SECS
) {
840 /* Timeout expired. */
841 sc
->sc_purging
= false;
843 /* Still purging. Adjust the caller's byte count. */
850 u3g_write(void *arg
, int portno
, u_char
*to
, u_char
*from
, u_int32_t
*count
)
852 struct u3g_softc
*sc
= arg
;
855 * Stop purging as soon as the first data is written to the device.
857 sc
->sc_purging
= false;
858 memcpy(to
, from
, *count
);