1 /* $NetBSD: u3g.c,v 1.7 2009/05/29 18:49:21 plunky Exp $ */ 2 3 /* 4 * Copyright (c) 2008 AnyWi Technologies 5 * Author: Andrea Guzzo <aguzzo@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.7 2009/05/29 18:49:21 plunky 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