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