u3g.c revision 1.4.4.1 1 1.1 joerg /*
2 1.1 joerg * Copyright (c) 2008 AnyWi Technologies
3 1.1 joerg * Author: Andrea Guzzo <aguzzo (at) anywi.com>
4 1.1 joerg * * based on uark.c 1.1 2006/08/14 08:30:22 jsg *
5 1.1 joerg * * parts from ubsa.c 183348 2008-09-25 12:00:56Z phk *
6 1.1 joerg *
7 1.1 joerg * Permission to use, copy, modify, and distribute this software for any
8 1.1 joerg * purpose with or without fee is hereby granted, provided that the above
9 1.1 joerg * copyright notice and this permission notice appear in all copies.
10 1.1 joerg *
11 1.1 joerg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 1.1 joerg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 1.1 joerg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 1.1 joerg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 1.1 joerg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 1.1 joerg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 1.1 joerg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 1.1 joerg *
19 1.1 joerg * $FreeBSD$
20 1.1 joerg */
21 1.1 joerg
22 1.1 joerg #include <sys/param.h>
23 1.1 joerg #include <sys/systm.h>
24 1.1 joerg #include <sys/kernel.h>
25 1.1 joerg #include <sys/malloc.h>
26 1.1 joerg #include <sys/module.h>
27 1.1 joerg #include <sys/bus.h>
28 1.1 joerg #include <sys/ioccom.h>
29 1.1 joerg #include <sys/fcntl.h>
30 1.1 joerg #include <sys/conf.h>
31 1.1 joerg #include <sys/tty.h>
32 1.1 joerg #include <sys/file.h>
33 1.1 joerg #include <sys/selinfo.h>
34 1.1 joerg
35 1.1 joerg #include <dev/usb/usb.h>
36 1.1 joerg #include <dev/usb/usbdi.h>
37 1.1 joerg #include <dev/usb/usbdivar.h>
38 1.1 joerg #include <dev/usb/usbdi_util.h>
39 1.1 joerg
40 1.1 joerg #include <dev/usb/ucomvar.h>
41 1.1 joerg
42 1.1 joerg #include "usbdevs.h"
43 1.1 joerg
44 1.1 joerg #define U3GBUFSZ 1024
45 1.1 joerg #define U3G_MAXPORTS 4
46 1.1 joerg
47 1.1 joerg struct u3g_softc {
48 1.1 joerg device_t sc_ucom[U3G_MAXPORTS];;
49 1.1 joerg device_t sc_dev;
50 1.1 joerg usbd_device_handle sc_udev;
51 1.1 joerg u_char sc_msr;
52 1.1 joerg u_char sc_lsr;
53 1.1 joerg u_char numports;
54 1.1 joerg
55 1.1 joerg usbd_interface_handle sc_intr_iface; /* interrupt interface */
56 1.1 joerg #ifdef U3G_DEBUG
57 1.1 joerg int sc_intr_number; /* interrupt number */
58 1.1 joerg usbd_pipe_handle sc_intr_pipe; /* interrupt pipe */
59 1.1 joerg u_char *sc_intr_buf; /* interrupt buffer */
60 1.1 joerg #endif
61 1.1 joerg int sc_isize;
62 1.2 joerg bool sc_pseudodev;
63 1.1 joerg };
64 1.1 joerg
65 1.1 joerg struct ucom_methods u3g_methods = {
66 1.1 joerg NULL,
67 1.1 joerg NULL,
68 1.1 joerg NULL,
69 1.1 joerg NULL,
70 1.1 joerg NULL,
71 1.1 joerg NULL,
72 1.1 joerg NULL,
73 1.1 joerg NULL,
74 1.1 joerg };
75 1.1 joerg
76 1.1 joerg static const struct usb_devno u3g_devs[] = {
77 1.1 joerg /* OEM: Option N.V. */
78 1.1 joerg { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_QUADPLUSUMTS },
79 1.1 joerg { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_HSDPA },
80 1.3 joerg { USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GTMAXHSUPA },
81 1.3 joerg /* OEM: Qualcomm, Inc. */
82 1.3 joerg { USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM },
83 1.1 joerg /* OEM: Huawei */
84 1.1 joerg { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },
85 1.1 joerg { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
86 1.1 joerg /* OEM: Novatel */
87 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 },
88 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_ES620 },
89 1.1 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D },
90 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U720 },
91 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U727 },
92 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINU740 },
93 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U740_2 },
94 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U870 },
95 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 },
96 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_S720 },
97 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_V740 },
98 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_X950D },
99 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_XU870 },
100 1.3 joerg { USB_VENDOR_DELL, USB_PRODUCT_DELL_W5500 },
101 1.3 joerg #if 0
102 1.3 joerg { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D_DRIVER },
103 1.3 joerg #endif
104 1.3 joerg /* OEM: Merlin */
105 1.3 joerg { USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 },
106 1.1 joerg
107 1.3 joerg /* OEM: Sierra Wireless: */
108 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 },
109 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 },
110 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U },
111 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E },
112 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 },
113 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 },
114 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E },
115 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U },
116 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 },
117 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E },
118 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U },
119 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 },
120 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 },
121 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 },
122 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 },
123 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725 },
124 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 },
125 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 },
126 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 },
127 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 },
128 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 },
129 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U },
130 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 },
131 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 },
132 1.3 joerg { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 },
133 1.1 joerg };
134 1.1 joerg
135 1.1 joerg #ifdef U3G_DEBUG
136 1.1 joerg static void
137 1.1 joerg u3g_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
138 1.1 joerg {
139 1.1 joerg struct u3g_softc *sc = (struct u3g_softc *)priv;
140 1.1 joerg aprint_normal_dev(sc->sc_dev, "INTERRUPT CALLBACK\n");
141 1.1 joerg }
142 1.1 joerg #endif
143 1.1 joerg
144 1.1 joerg static int
145 1.2 joerg u3g_novatel_reinit(struct usb_attach_arg *uaa)
146 1.2 joerg {
147 1.2 joerg unsigned char cmd[31];
148 1.2 joerg usbd_interface_handle iface;
149 1.2 joerg usb_interface_descriptor_t *id;
150 1.2 joerg usb_endpoint_descriptor_t *ed;
151 1.2 joerg usbd_pipe_handle pipe;
152 1.2 joerg usbd_xfer_handle xfer;
153 1.2 joerg int err, i;
154 1.2 joerg
155 1.2 joerg memset(cmd, 0, sizeof(cmd));
156 1.2 joerg /* Byte 0..3: Command Block Wrapper (CBW) signature */
157 1.2 joerg cmd[0] = 0x55;
158 1.2 joerg cmd[1] = 0x53;
159 1.2 joerg cmd[2] = 0x42;
160 1.2 joerg cmd[3] = 0x43;
161 1.2 joerg /* 4..7: CBW Tag, has to unique, but only a single transfer used. */
162 1.2 joerg cmd[4] = 0x01;
163 1.2 joerg /* 8..11: CBW Transfer Length, no data here */
164 1.2 joerg /* 12: CBW Flag: output, so 0 */
165 1.2 joerg /* 13: CBW Lun: 0 */
166 1.2 joerg /* 14: CBW Length */
167 1.2 joerg cmd[14] = 0x06;
168 1.2 joerg /* Rest is the SCSI payload */
169 1.2 joerg /* 0: SCSI START/STOP opcode */
170 1.2 joerg cmd[15] = 0x1b;
171 1.2 joerg /* 1..3 unused */
172 1.2 joerg /* 4 Load/Eject command */
173 1.2 joerg cmd[19] = 0x02;
174 1.2 joerg /* 5: unused */
175 1.2 joerg
176 1.2 joerg
177 1.2 joerg /* Move the device into the configured state. */
178 1.2 joerg err = usbd_set_config_index(uaa->device, 0, 0);
179 1.2 joerg if (err) {
180 1.2 joerg aprint_error("u3g: failed to set configuration index\n");
181 1.2 joerg return UMATCH_NONE;
182 1.2 joerg }
183 1.2 joerg
184 1.2 joerg err = usbd_device2interface_handle(uaa->device, 0, &iface);
185 1.2 joerg if (err != 0) {
186 1.2 joerg aprint_error("u3g: failed to get interface\n");
187 1.2 joerg return UMATCH_NONE;
188 1.2 joerg }
189 1.2 joerg
190 1.2 joerg id = usbd_get_interface_descriptor(iface);
191 1.2 joerg ed = NULL;
192 1.2 joerg for (i = 0 ; i < id->bNumEndpoints ; i++) {
193 1.2 joerg ed = usbd_interface2endpoint_descriptor(iface, i);
194 1.2 joerg if (ed == NULL)
195 1.2 joerg continue;
196 1.2 joerg if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT)
197 1.2 joerg continue;
198 1.2 joerg if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK)
199 1.2 joerg break;
200 1.2 joerg }
201 1.2 joerg
202 1.2 joerg if (i == id->bNumEndpoints)
203 1.2 joerg return UMATCH_NONE;
204 1.2 joerg
205 1.2 joerg err = usbd_open_pipe(iface, ed->bEndpointAddress, USBD_EXCLUSIVE_USE,
206 1.2 joerg &pipe);
207 1.2 joerg if (err != 0) {
208 1.2 joerg aprint_error("u3g: failed to open bulk transfer pipe %d\n",
209 1.2 joerg ed->bEndpointAddress);
210 1.2 joerg return UMATCH_NONE;
211 1.2 joerg }
212 1.2 joerg
213 1.2 joerg xfer = usbd_alloc_xfer(uaa->device);
214 1.2 joerg if (xfer != NULL) {
215 1.2 joerg usbd_setup_xfer(xfer, pipe, NULL, cmd, sizeof(cmd),
216 1.2 joerg USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL);
217 1.2 joerg
218 1.2 joerg err = usbd_transfer(xfer);
219 1.2 joerg if (err)
220 1.2 joerg aprint_error("u3g: transfer failed\n");
221 1.2 joerg usbd_free_xfer(xfer);
222 1.2 joerg } else {
223 1.2 joerg aprint_error("u3g: failed to allocate xfer\n");
224 1.2 joerg err = USBD_NOMEM;
225 1.2 joerg }
226 1.2 joerg
227 1.2 joerg usbd_abort_pipe(pipe);
228 1.2 joerg usbd_close_pipe(pipe);
229 1.2 joerg
230 1.2 joerg return (err == USBD_NORMAL_COMPLETION ? UMATCH_HIGHEST : UMATCH_NONE);
231 1.2 joerg }
232 1.2 joerg
233 1.2 joerg static int
234 1.1 joerg u3g_huawei_reinit(usbd_device_handle dev)
235 1.1 joerg {
236 1.1 joerg /* The Huawei device presents itself as a umass device with Windows
237 1.1 joerg * drivers on it. After installation of the driver, it reinits into a
238 1.1 joerg * 3G serial device.
239 1.1 joerg */
240 1.1 joerg usb_device_request_t req;
241 1.1 joerg usb_config_descriptor_t *cdesc;
242 1.1 joerg
243 1.1 joerg /* Get the config descriptor */
244 1.1 joerg cdesc = usbd_get_config_descriptor(dev);
245 1.1 joerg if (cdesc == NULL)
246 1.1 joerg return (UMATCH_NONE);
247 1.1 joerg
248 1.1 joerg /* One iface means umass mode, more than 1 (4 usually) means 3G mode */
249 1.1 joerg if (cdesc->bNumInterface > 1)
250 1.1 joerg return (UMATCH_VENDOR_PRODUCT);
251 1.1 joerg
252 1.1 joerg req.bmRequestType = UT_WRITE_DEVICE;
253 1.1 joerg req.bRequest = UR_SET_FEATURE;
254 1.1 joerg USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
255 1.1 joerg USETW(req.wIndex, UHF_PORT_SUSPEND);
256 1.1 joerg USETW(req.wLength, 0);
257 1.1 joerg
258 1.1 joerg (void) usbd_do_request(dev, &req, 0);
259 1.1 joerg
260 1.2 joerg
261 1.2 joerg return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */
262 1.1 joerg }
263 1.1 joerg
264 1.1 joerg static int
265 1.4 christos u3g_sierra_reinit(usbd_device_handle dev)
266 1.4 christos {
267 1.4 christos /* Some Sierra devices presents themselves as a umass device with
268 1.4 christos * Windows drivers on it. After installation of the driver, it
269 1.4 christos * reinits into a * 3G serial device.
270 1.4 christos */
271 1.4 christos usb_device_request_t req;
272 1.4 christos usb_config_descriptor_t *cdesc;
273 1.4 christos
274 1.4 christos /* Get the config descriptor */
275 1.4 christos cdesc = usbd_get_config_descriptor(dev);
276 1.4 christos if (cdesc == NULL)
277 1.4 christos return (UMATCH_NONE);
278 1.4 christos
279 1.4 christos req.bmRequestType = UT_VENDOR;
280 1.4 christos req.bRequest = UR_SET_INTERFACE;
281 1.4 christos USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
282 1.4 christos USETW(req.wIndex, UHF_PORT_CONNECTION);
283 1.4 christos USETW(req.wLength, 0);
284 1.4 christos
285 1.4 christos (void) usbd_do_request(dev, &req, 0);
286 1.4 christos
287 1.4 christos return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */
288 1.4 christos }
289 1.4 christos
290 1.4 christos static int
291 1.1 joerg u3g_match(device_t parent, cfdata_t match, void *aux)
292 1.1 joerg {
293 1.1 joerg struct usb_attach_arg *uaa = aux;
294 1.1 joerg
295 1.1 joerg if (uaa->vendor == USB_VENDOR_HUAWEI)
296 1.1 joerg return u3g_huawei_reinit(uaa->device);
297 1.1 joerg
298 1.2 joerg if (uaa->vendor == USB_VENDOR_NOVATEL2 &&
299 1.2 joerg uaa->product == USB_PRODUCT_NOVATEL2_MC950D_DRIVER)
300 1.2 joerg return u3g_novatel_reinit(uaa);
301 1.2 joerg
302 1.4 christos if (uaa->vendor == USB_VENDOR_SIERRA &&
303 1.4 christos uaa->product == USB_PRODUCT_SIERRA_INSTALLER)
304 1.4 christos return u3g_sierra_reinit(uaa->device);
305 1.4 christos
306 1.1 joerg if (usb_lookup(u3g_devs, uaa->vendor, uaa->product))
307 1.1 joerg return UMATCH_VENDOR_PRODUCT;
308 1.1 joerg
309 1.1 joerg return UMATCH_NONE;
310 1.1 joerg }
311 1.1 joerg
312 1.1 joerg static void
313 1.1 joerg u3g_attach(device_t parent, device_t self, void *aux)
314 1.1 joerg {
315 1.1 joerg struct u3g_softc *sc = device_private(self);
316 1.1 joerg struct usb_attach_arg *uaa = aux;
317 1.1 joerg usbd_device_handle dev = uaa->device;
318 1.1 joerg usbd_interface_handle iface;
319 1.1 joerg usb_interface_descriptor_t *id;
320 1.1 joerg usb_endpoint_descriptor_t *ed;
321 1.1 joerg usbd_status error;
322 1.1 joerg int i, n;
323 1.1 joerg usb_config_descriptor_t *cdesc;
324 1.1 joerg
325 1.1 joerg aprint_naive("\n");
326 1.1 joerg aprint_normal("\n");
327 1.1 joerg
328 1.2 joerg if (uaa->vendor == USB_VENDOR_NOVATEL2 &&
329 1.2 joerg uaa->product == USB_PRODUCT_NOVATEL2_MC950D_DRIVER) {
330 1.2 joerg /* About to disappear... */
331 1.2 joerg sc->sc_pseudodev = true;
332 1.2 joerg return;
333 1.2 joerg }
334 1.2 joerg
335 1.1 joerg sc->sc_dev = self;
336 1.1 joerg #ifdef U3G_DEBUG
337 1.1 joerg sc->sc_intr_number = -1;
338 1.1 joerg sc->sc_intr_pipe = NULL;
339 1.1 joerg #endif
340 1.1 joerg /* Move the device into the configured state. */
341 1.1 joerg error = usbd_set_config_index(dev, 0, 1);
342 1.1 joerg if (error) {
343 1.1 joerg aprint_error_dev(self, "failed to set configuration: %s\n",
344 1.1 joerg usbd_errstr(error));
345 1.1 joerg return;
346 1.1 joerg }
347 1.1 joerg
348 1.1 joerg /* get the config descriptor */
349 1.1 joerg cdesc = usbd_get_config_descriptor(dev);
350 1.1 joerg
351 1.1 joerg if (cdesc == NULL) {
352 1.1 joerg aprint_error_dev(self, "failed to get configuration descriptor\n");
353 1.1 joerg return;
354 1.1 joerg }
355 1.1 joerg
356 1.2 joerg if (uaa->vendor == USB_VENDOR_HUAWEI && cdesc->bNumInterface > 1) {
357 1.2 joerg /* About to disappear... */
358 1.2 joerg sc->sc_pseudodev = true;
359 1.2 joerg return;
360 1.2 joerg }
361 1.2 joerg
362 1.4 christos if (uaa->vendor == USB_VENDOR_SIERRA &&
363 1.4 christos uaa->product == USB_PRODUCT_SIERRA_INSTALLER) {
364 1.4 christos /* About to disappear... */
365 1.4 christos sc->sc_pseudodev = true;
366 1.4 christos return;
367 1.4 christos }
368 1.4 christos
369 1.1 joerg sc->sc_udev = dev;
370 1.1 joerg sc->numports = (cdesc->bNumInterface <= U3G_MAXPORTS)?cdesc->bNumInterface:U3G_MAXPORTS;
371 1.1 joerg for ( i = 0; i < sc->numports; i++ ) {
372 1.1 joerg struct ucom_attach_args uca;
373 1.1 joerg
374 1.1 joerg error = usbd_device2interface_handle(dev, i, &iface);
375 1.1 joerg if (error) {
376 1.1 joerg aprint_error_dev(self,
377 1.1 joerg "failed to get interface, err=%s\n",
378 1.1 joerg usbd_errstr(error));
379 1.1 joerg return;
380 1.1 joerg }
381 1.1 joerg id = usbd_get_interface_descriptor(iface);
382 1.1 joerg
383 1.1 joerg uca.info = "Generic 3G Serial Device";
384 1.1 joerg uca.ibufsize = U3GBUFSZ;
385 1.1 joerg uca.obufsize = U3GBUFSZ;
386 1.1 joerg uca.ibufsizepad = U3GBUFSZ;
387 1.1 joerg uca.portno = i;
388 1.1 joerg uca.opkthdrlen = 0;
389 1.1 joerg uca.device = dev;
390 1.1 joerg uca.iface = iface;
391 1.1 joerg uca.methods = &u3g_methods;
392 1.1 joerg uca.arg = sc;
393 1.1 joerg
394 1.1 joerg uca.bulkin = uca.bulkout = -1;
395 1.1 joerg for (n = 0; n < id->bNumEndpoints; n++) {
396 1.1 joerg ed = usbd_interface2endpoint_descriptor(iface, n);
397 1.1 joerg if (ed == NULL) {
398 1.1 joerg aprint_error_dev(self,
399 1.1 joerg "could not read endpoint descriptor\n");
400 1.1 joerg return;
401 1.1 joerg }
402 1.1 joerg if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
403 1.1 joerg UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
404 1.1 joerg uca.bulkin = ed->bEndpointAddress;
405 1.1 joerg else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
406 1.1 joerg UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
407 1.1 joerg uca.bulkout = ed->bEndpointAddress;
408 1.1 joerg }
409 1.1 joerg if (uca.bulkin == -1 || uca.bulkout == -1) {
410 1.1 joerg aprint_error_dev(self, "missing endpoint\n");
411 1.1 joerg return;
412 1.1 joerg }
413 1.1 joerg
414 1.1 joerg sc->sc_ucom[i] = config_found_sm_loc(self, "ucombus", NULL, &uca,
415 1.1 joerg ucomprint, ucomsubmatch);
416 1.1 joerg }
417 1.1 joerg
418 1.1 joerg #ifdef U3G_DEBUG
419 1.1 joerg if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
420 1.1 joerg sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
421 1.1 joerg error = usbd_open_pipe_intr(sc->sc_intr_iface,
422 1.1 joerg sc->sc_intr_number,
423 1.1 joerg USBD_SHORT_XFER_OK,
424 1.1 joerg &sc->sc_intr_pipe,
425 1.1 joerg sc,
426 1.1 joerg sc->sc_intr_buf,
427 1.1 joerg sc->sc_isize,
428 1.1 joerg u3g_intr,
429 1.1 joerg 100);
430 1.1 joerg if (error) {
431 1.1 joerg aprint_error_dev(self,
432 1.1 joerg "cannot open interrupt pipe (addr %d)\n",
433 1.1 joerg sc->sc_intr_number);
434 1.1 joerg return;
435 1.1 joerg }
436 1.1 joerg }
437 1.1 joerg #endif
438 1.1 joerg
439 1.1 joerg
440 1.1 joerg if (!pmf_device_register(self, NULL, NULL))
441 1.1 joerg aprint_error_dev(self, "couldn't establish power handler\n");
442 1.1 joerg }
443 1.1 joerg
444 1.1 joerg static int
445 1.1 joerg u3g_detach(device_t self, int flags)
446 1.1 joerg {
447 1.1 joerg struct u3g_softc *sc = device_private(self);
448 1.1 joerg int rv = 0;
449 1.1 joerg int i;
450 1.1 joerg
451 1.2 joerg if (sc->sc_pseudodev)
452 1.2 joerg return 0;
453 1.2 joerg
454 1.1 joerg pmf_device_deregister(self);
455 1.1 joerg
456 1.1 joerg for (i = 0; i < sc->numports; i++) {
457 1.1 joerg if(sc->sc_ucom[i]) {
458 1.1 joerg rv = config_detach(sc->sc_ucom[i], flags);
459 1.1 joerg if(rv != 0) {
460 1.1 joerg aprint_verbose_dev(self, "Can't deallocat port %d", i);
461 1.1 joerg return rv;
462 1.1 joerg }
463 1.1 joerg }
464 1.1 joerg }
465 1.1 joerg
466 1.1 joerg #ifdef U3G_DEBUG
467 1.1 joerg if (sc->sc_intr_pipe != NULL) {
468 1.1 joerg int err = usbd_abort_pipe(sc->sc_intr_pipe);
469 1.1 joerg if (err)
470 1.1 joerg aprint_error_dev(self,
471 1.1 joerg "abort interrupt pipe failed: %s\n",
472 1.1 joerg usbd_errstr(err));
473 1.1 joerg err = usbd_close_pipe(sc->sc_intr_pipe);
474 1.1 joerg if (err)
475 1.1 joerg aprint_error_dev(self,
476 1.1 joerg "close interrupt pipe failed: %s\n",
477 1.1 joerg usbd_errstr(err));
478 1.1 joerg free(sc->sc_intr_buf, M_USBDEV);
479 1.1 joerg sc->sc_intr_pipe = NULL;
480 1.1 joerg }
481 1.1 joerg #endif
482 1.1 joerg
483 1.1 joerg return 0;
484 1.1 joerg }
485 1.1 joerg
486 1.1 joerg static void
487 1.1 joerg u3g_childdet(device_t self, device_t child)
488 1.1 joerg {
489 1.1 joerg struct u3g_softc *sc = device_private(self);
490 1.1 joerg int i;
491 1.1 joerg
492 1.1 joerg for (i = 0; i < sc->numports; i++) {
493 1.1 joerg if (sc->sc_ucom[i] == child)
494 1.1 joerg sc->sc_ucom[i] = NULL;
495 1.1 joerg }
496 1.1 joerg }
497 1.1 joerg
498 1.1 joerg static int
499 1.1 joerg u3g_activate(device_t self, enum devact act)
500 1.1 joerg {
501 1.1 joerg struct u3g_softc *sc = device_private(self);
502 1.1 joerg int i, rv = 0;
503 1.1 joerg
504 1.1 joerg switch (act) {
505 1.1 joerg case DVACT_ACTIVATE:
506 1.1 joerg return (EOPNOTSUPP);
507 1.1 joerg break;
508 1.1 joerg
509 1.1 joerg case DVACT_DEACTIVATE:
510 1.1 joerg for (i = 0; i < sc->numports; i++) {
511 1.1 joerg if (sc->sc_ucom[i] && config_deactivate(sc->sc_ucom[i]))
512 1.1 joerg rv = -1;
513 1.1 joerg }
514 1.1 joerg break;
515 1.1 joerg }
516 1.1 joerg return (rv);
517 1.1 joerg }
518 1.1 joerg
519 1.1 joerg CFATTACH_DECL2_NEW(u3g, sizeof(struct u3g_softc), u3g_match,
520 1.1 joerg u3g_attach, u3g_detach, u3g_activate, NULL, u3g_childdet);
521