1 /* $NetBSD: ubsa.c,v 1.24 2009/09/23 19:07:19 plunky Exp $ */
3 * Copyright (c) 2002, Alexander Kabaev <kan.FreeBSD.org>.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * Copyright (c) 2001 The NetBSD Foundation, Inc.
29 * All rights reserved.
31 * This code is derived from software contributed to The NetBSD Foundation
32 * by Ichiro FUKUHARA (ichiro@ichiro.org).
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
43 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
44 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
45 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
46 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
47 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
48 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
49 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
51 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
53 * POSSIBILITY OF SUCH DAMAGE.
56 #include <sys/cdefs.h>
57 __KERNEL_RCSID(0, "$NetBSD: ubsa.c,v 1.24 2009/09/23 19:07:19 plunky Exp $");
59 #include <sys/param.h>
60 #include <sys/systm.h>
61 #include <sys/kernel.h>
62 #include <sys/malloc.h>
66 #include <sys/ioccom.h>
67 #include <sys/fcntl.h>
71 #if __FreeBSD_version >= 500014
72 #include <sys/selinfo.h>
74 #include <sys/select.h>
77 #include <sys/device.h>
79 #include <sys/sysctl.h>
81 #include <dev/usb/usb.h>
82 #include <dev/usb/usbcdc.h>
84 #include <dev/usb/usbdi.h>
85 #include <dev/usb/usbdi_util.h>
86 #include <dev/usb/usbdevs.h>
87 #include <dev/usb/usb_quirks.h>
89 #include <dev/usb/ucomvar.h>
90 #include <dev/usb/ubsavar.h>
93 Static
int ubsadebug
= 0;
95 SYSCTL_NODE(_hw_usb
, OID_AUTO
, ubsa
, CTLFLAG_RW
, 0, "USB ubsa");
96 SYSCTL_INT(_hw_usb_ubsa
, OID_AUTO
, debug
, CTLFLAG_RW
,
97 &ubsadebug
, 0, "ubsa debug level");
100 #define DPRINTFN(n, x) do { \
101 if (ubsadebug > (n)) \
105 #define DPRINTFN(n, x)
107 #define DPRINTF(x) DPRINTFN(0, x)
109 struct ucom_methods ubsa_methods
= {
120 Static
const struct usb_devno ubsa_devs
[] = {
122 { USB_VENDOR_BELKIN
, USB_PRODUCT_BELKIN_F5U103
},
124 { USB_VENDOR_BELKIN
, USB_PRODUCT_BELKIN_F5U120
},
125 /* GoHubs GO-COM232 */
126 { USB_VENDOR_ETEK
, USB_PRODUCT_ETEK_1COM
},
127 /* GoHubs GO-COM232 */
128 { USB_VENDOR_GOHUBS
, USB_PRODUCT_GOHUBS_GOCOM232
},
130 { USB_VENDOR_PERACOM
, USB_PRODUCT_PERACOM_SERIAL1
},
132 { USB_VENDOR_OPTIONNV
, USB_PRODUCT_OPTIONNV_MC3G
},
133 { USB_VENDOR_OPTIONNV
, USB_PRODUCT_OPTIONNV_QUADUMTS2
},
134 { USB_VENDOR_OPTIONNV
, USB_PRODUCT_OPTIONNV_QUADUMTS
},
135 /* AnyDATA ADU-E100H */
136 { USB_VENDOR_ANYDATA
, USB_PRODUCT_ANYDATA_ADU_E100H
},
138 #define ubsa_lookup(v, p) usb_lookup(ubsa_devs, v, p)
140 int ubsa_match(device_t
, cfdata_t
, void *);
141 void ubsa_attach(device_t
, device_t
, void *);
142 void ubsa_childdet(device_t
, device_t
);
143 int ubsa_detach(device_t
, int);
144 int ubsa_activate(device_t
, enum devact
);
146 extern struct cfdriver ubsa_cd
;
148 CFATTACH_DECL2_NEW(ubsa
, sizeof(struct ubsa_softc
),
149 ubsa_match
, ubsa_attach
, ubsa_detach
, ubsa_activate
, NULL
, ubsa_childdet
);
153 USB_MATCH_START(ubsa
, uaa
);
155 return (ubsa_lookup(uaa
->vendor
, uaa
->product
) != NULL
?
156 UMATCH_VENDOR_PRODUCT
: UMATCH_NONE
);
161 USB_ATTACH_START(ubsa
, sc
, uaa
);
162 usbd_device_handle dev
= uaa
->device
;
163 usb_config_descriptor_t
*cdesc
;
164 usb_interface_descriptor_t
*id
;
165 usb_endpoint_descriptor_t
*ed
;
168 struct ucom_attach_args uca
;
176 devinfop
= usbd_devinfo_alloc(dev
, 0);
177 aprint_normal_dev(self
, "%s\n", devinfop
);
178 usbd_devinfo_free(devinfop
);
181 sc
->sc_config_index
= UBSA_DEFAULT_CONFIG_INDEX
;
182 sc
->sc_numif
= 1; /* default device has one interface */
185 * initialize rts, dtr variables to something
186 * different from boolean 0, 1
192 * Quad UMTS cards use different requests to
193 * control com settings and only some.
196 if (uaa
->vendor
== USB_VENDOR_OPTIONNV
) {
197 switch (uaa
->product
) {
198 case USB_PRODUCT_OPTIONNV_QUADUMTS
:
199 case USB_PRODUCT_OPTIONNV_QUADUMTS2
:
205 DPRINTF(("ubsa attach: sc = %p\n", sc
));
207 /* Move the device into the configured state. */
208 err
= usbd_set_config_index(dev
, sc
->sc_config_index
, 1);
210 aprint_error_dev(self
,
211 "failed to set configuration: %s\n",
217 /* get the config descriptor */
218 cdesc
= usbd_get_config_descriptor(sc
->sc_udev
);
221 aprint_error_dev(self
,
222 "failed to get configuration descriptor\n");
227 sc
->sc_intr_number
= -1;
228 sc
->sc_intr_pipe
= NULL
;
230 /* get the interfaces */
231 err
= usbd_device2interface_handle(dev
, UBSA_IFACE_INDEX_OFFSET
,
234 /* can not get main interface */
239 /* Find the endpoints */
240 id
= usbd_get_interface_descriptor(sc
->sc_iface
[0]);
241 sc
->sc_iface_number
[0] = id
->bInterfaceNumber
;
243 /* initialize endpoints */
244 uca
.bulkin
= uca
.bulkout
= -1;
246 for (i
= 0; i
< id
->bNumEndpoints
; i
++) {
247 ed
= usbd_interface2endpoint_descriptor(sc
->sc_iface
[0], i
);
249 aprint_error_dev(self
,
250 "no endpoint descriptor for %d\n", i
);
254 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
255 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_INTERRUPT
) {
256 sc
->sc_intr_number
= ed
->bEndpointAddress
;
257 sc
->sc_isize
= UGETW(ed
->wMaxPacketSize
);
258 } else if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
259 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
260 uca
.bulkin
= ed
->bEndpointAddress
;
261 uca
.ibufsize
= UGETW(ed
->wMaxPacketSize
);
262 } else if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_OUT
&&
263 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
264 uca
.bulkout
= ed
->bEndpointAddress
;
265 uca
.obufsize
= UGETW(ed
->wMaxPacketSize
);
267 } /* end of Endpoint loop */
269 if (sc
->sc_intr_number
== -1) {
270 aprint_error_dev(self
, "Could not find interrupt in\n");
275 if (uca
.bulkin
== -1) {
276 aprint_error_dev(self
, "Could not find data bulk in\n");
281 if (uca
.bulkout
== -1) {
282 aprint_error_dev(self
, "Could not find data bulk out\n");
288 /* bulkin, bulkout set above */
289 uca
.ibufsizepad
= uca
.ibufsize
;
292 uca
.iface
= sc
->sc_iface
[0];
293 uca
.methods
= &ubsa_methods
;
296 DPRINTF(("ubsa: int#=%d, in = 0x%x, out = 0x%x, intr = 0x%x\n",
297 i
, uca
.bulkin
, uca
.bulkout
, sc
->sc_intr_number
));
298 sc
->sc_subdevs
[0] = config_found_sm_loc(self
, "ucombus", NULL
, &uca
,
299 ucomprint
, ucomsubmatch
);
301 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH
, sc
->sc_udev
,
304 USB_ATTACH_SUCCESS_RETURN
;
307 USB_ATTACH_ERROR_RETURN
;
312 ubsa_childdet(device_t self
, device_t child
)
315 struct ubsa_softc
*sc
= device_private(self
);
317 for (i
= 0; i
< sc
->sc_numif
; i
++) {
318 if (sc
->sc_subdevs
[i
] == child
)
321 KASSERT(i
< sc
->sc_numif
);
322 sc
->sc_subdevs
[i
] = NULL
;
327 USB_DETACH_START(ubsa
, sc
);
332 DPRINTF(("ubsa_detach: sc = %p\n", sc
));
334 if (sc
->sc_intr_pipe
!= NULL
) {
335 usbd_abort_pipe(sc
->sc_intr_pipe
);
336 usbd_close_pipe(sc
->sc_intr_pipe
);
337 free(sc
->sc_intr_buf
, M_USBDEV
);
338 sc
->sc_intr_pipe
= NULL
;
342 for (i
= 0; i
< sc
->sc_numif
; i
++) {
343 if (sc
->sc_subdevs
[i
] != NULL
)
344 rv
|= config_detach(sc
->sc_subdevs
[i
], flags
);
347 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH
, sc
->sc_udev
,
354 ubsa_activate(device_ptr_t self
, enum devact act
)
356 struct ubsa_softc
*sc
= device_private(self
);
359 case DVACT_DEACTIVATE
: