1 /* $OpenBSD: umsm.c,v 1.79 2011/07/22 11:37:09 dcoppa Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Yojiro UO <yuo@nui.org> 5 * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Driver for Qualcomm MSM EVDO and UMTS communication devices */ 21 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/kernel.h> 25 #include <sys/malloc.h> 26 #include <sys/device.h> 27 #include <sys/conf.h> 28 #include <sys/tty.h> 29 30 #include <dev/usb/usb.h> 31 #include <dev/usb/usbdi.h> 32 #include <dev/usb/usbdi_util.h> 33 #include <dev/usb/usbdevs.h> 34 #include <dev/usb/ucomvar.h> 35 #include <dev/usb/usbcdc.h> 36 #include <dev/usb/umassvar.h> 37 #undef DPRINTF /* undef DPRINTF for umass */ 38 39 #ifdef USB_DEBUG 40 #define UMSM_DEBUG 41 #endif 42 43 #ifdef UMSM_DEBUG 44 int umsmdebug = 0; 45 #define DPRINTFN(n, x) do { if (umsmdebug > (n)) printf x; } while (0) 46 #else 47 #define DPRINTFN(n, x) 48 #endif 49 50 #define DPRINTF(x) DPRINTFN(0, x) 51 52 #define UMSMBUFSZ 4096 53 #define UMSM_INTR_INTERVAL 100 /* ms */ 54 #define E220_MODE_CHANGE_REQUEST 0x2 55 #define TRUINSTALL_CHANGEMODE_REQUEST 0x0b 56 57 int umsm_match(struct device *, void *, void *); 58 void umsm_attach(struct device *, struct device *, void *); 59 int umsm_detach(struct device *, int); 60 int umsm_activate(struct device *, int); 61 62 int umsm_open(void *, int); 63 void umsm_close(void *, int); 64 void umsm_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); 65 void umsm_get_status(void *, int, u_char *, u_char *); 66 void umsm_set(void *, int, int, int); 67 68 struct umsm_softc { 69 struct device sc_dev; 70 usbd_device_handle sc_udev; 71 usbd_interface_handle sc_iface; 72 int sc_iface_no; 73 struct device *sc_subdev; 74 u_char sc_dying; 75 uint16_t sc_flag; 76 77 /* interrupt ep */ 78 int sc_intr_number; 79 usbd_pipe_handle sc_intr_pipe; 80 u_char *sc_intr_buf; 81 int sc_isize; 82 83 u_char sc_lsr; /* Local status register */ 84 u_char sc_msr; /* status register */ 85 u_char sc_dtr; /* current DTR state */ 86 u_char sc_rts; /* current RTS state */ 87 }; 88 89 usbd_status umsm_huawei_changemode(usbd_device_handle); 90 usbd_status umsm_truinstall_changemode(usbd_device_handle); 91 usbd_status umsm_umass_changemode(struct umsm_softc *); 92 93 struct ucom_methods umsm_methods = { 94 umsm_get_status, 95 umsm_set, 96 NULL, 97 NULL, 98 umsm_open, 99 umsm_close, 100 NULL, 101 NULL, 102 }; 103 104 struct umsm_type { 105 struct usb_devno umsm_dev; 106 uint16_t umsm_flag; 107 /* device type */ 108 #define DEV_NORMAL 0x0000 109 #define DEV_HUAWEI 0x0001 110 #define DEV_TRUINSTALL 0x0002 111 #define DEV_UMASS1 0x0010 112 #define DEV_UMASS2 0x0020 113 #define DEV_UMASS3 0x0040 114 #define DEV_UMASS4 0x0080 115 #define DEV_UMASS5 0x0100 116 #define DEV_UMASS6 0x0200 117 #define DEV_UMASS7 0x0400 118 #define DEV_UMASS (DEV_UMASS1 | DEV_UMASS2 | DEV_UMASS3 | DEV_UMASS4 | \ 119 DEV_UMASS5 | DEV_UMASS6 | DEV_UMASS7) 120 }; 121 122 static const struct umsm_type umsm_devs[] = { 123 {{ USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220 }, 0}, 124 125 {{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_A2502 }, 0}, 126 {{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_500A }, 0}, 127 {{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_E100H }, 0}, 128 129 {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_EU870D }, 0}, 130 {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_U740 }, 0}, 131 {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_W5500 }, 0}, 132 133 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E161 }, DEV_UMASS5}, 134 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E180 }, DEV_HUAWEI}, 135 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E181 }, DEV_HUAWEI}, 136 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E182 }, DEV_UMASS5}, 137 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E1820 }, DEV_UMASS5}, 138 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 }, DEV_HUAWEI}, 139 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E510 }, DEV_HUAWEI}, 140 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E618 }, DEV_HUAWEI}, 141 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_Mobile }, DEV_HUAWEI}, 142 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_K3765_INIT }, DEV_UMASS5}, 143 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_K3765 }, 0}, 144 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E1750 }, DEV_UMASS5}, 145 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E1752 }, 0}, 146 147 {{ USB_VENDOR_HYUNDAI, USB_PRODUCT_HYUNDAI_UM175 }, 0}, 148 149 {{ USB_VENDOR_LONGCHEER, USB_PRODUCT_LONGCHEER_D21LCMASS }, DEV_UMASS3}, 150 {{ USB_VENDOR_LONGCHEER, USB_PRODUCT_LONGCHEER_D21LC }, 0}, 151 152 {{ USB_VENDOR_KYOCERA2, USB_PRODUCT_KYOCERA2_KPC650 }, 0}, 153 154 /* XXX Some qualcomm devices are missing */ 155 {{ USB_VENDOR_QUALCOMM, USB_PRODUCT_QUALCOMM_MSM_DRIVER }, DEV_UMASS1}, 156 {{ USB_VENDOR_QUALCOMM, USB_PRODUCT_QUALCOMM_MSM_HSDPA }, 0}, 157 {{ USB_VENDOR_QUALCOMM, USB_PRODUCT_QUALCOMM_MSM_HSDPA2 }, 0}, 158 159 {{ USB_VENDOR_QUANTA2, USB_PRODUCT_QUANTA2_UMASS }, DEV_UMASS4}, 160 {{ USB_VENDOR_QUANTA2, USB_PRODUCT_QUANTA2_Q101 }, 0}, 161 162 {{ USB_VENDOR_ZTE, USB_PRODUCT_ZTE_AC2746 }, 0}, 163 {{ USB_VENDOR_ZTE, USB_PRODUCT_ZTE_UMASS_INSTALLER }, DEV_UMASS4}, 164 {{ USB_VENDOR_ZTE, USB_PRODUCT_ZTE_UMASS_INSTALLER2 }, DEV_UMASS6}, 165 {{ USB_VENDOR_ZTE, USB_PRODUCT_ZTE_UMASS_INSTALLER3 }, DEV_UMASS7}, 166 {{ USB_VENDOR_ZTE, USB_PRODUCT_ZTE_K3565Z }, 0}, 167 {{ USB_VENDOR_ZTE, USB_PRODUCT_ZTE_MF112 }, DEV_UMASS4}, 168 {{ USB_VENDOR_ZTE, USB_PRODUCT_ZTE_MF633 }, 0}, 169 {{ USB_VENDOR_ZTE, USB_PRODUCT_ZTE_MF637 }, 0}, 170 {{ USB_VENDOR_ZTE, USB_PRODUCT_ZTE_MSA110UP }, 0}, 171 172 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_EXPRESSCARD }, 0}, 173 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MERLINV620 }, 0}, 174 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MERLINV740 }, 0}, 175 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720 }, 0}, 176 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MERLINU740 }, 0}, 177 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MERLINU740_2 }, 0}, 178 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870 }, 0}, 179 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870 }, 0}, 180 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_EU870D }, 0}, 181 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D }, 0}, 182 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620 }, 0}, 183 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720 }, 0}, 184 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727 }, DEV_UMASS1}, 185 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D }, 0}, 186 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MERLINX950D }, DEV_UMASS4}, 187 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ZEROCD2 }, DEV_UMASS4}, 188 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U760 }, DEV_UMASS4}, 189 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC760 }, 0}, 190 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC760CD }, DEV_UMASS4}, 191 192 {{ USB_VENDOR_NOVATEL1, USB_PRODUCT_NOVATEL1_FLEXPACKGPS }, 0}, 193 194 {{ USB_VENDOR_NOKIA2, USB_PRODUCT_NOKIA2_CS15UMASS }, DEV_UMASS4}, 195 {{ USB_VENDOR_NOKIA2, USB_PRODUCT_NOKIA2_CS15 }, 0}, 196 197 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GFUSION }, 0}, 198 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS }, 0}, 199 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD }, 0}, 200 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUADPLUS }, 0}, 201 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GSICON72 }, DEV_UMASS1}, 202 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTHSDPA225 }, DEV_UMASS2}, 203 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTHSUPA380E }, 0}, 204 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36 }, 0}, 205 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_SCORPION }, 0}, 206 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G }, 0}, 207 208 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 }, 0}, 209 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 }, 0}, 210 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD_595 }, 0}, 211 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 }, 0}, 212 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E }, 0}, 213 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 }, 0}, 214 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U }, 0}, 215 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD_580 }, 0}, 216 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 }, 0}, 217 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725_2 }, 0}, 218 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 }, 0}, 219 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 }, 0}, 220 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 }, 0}, 221 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775 }, 0}, 222 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 }, 0}, 223 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 }, 0}, 224 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD_875 }, 0}, 225 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 }, 0}, 226 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 }, 0}, 227 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8790 }, 0}, 228 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 }, 0}, 229 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 }, 0}, 230 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E }, 0}, 231 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E }, 0}, 232 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U }, 0}, 233 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U }, 0}, 234 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC885U }, 0}, 235 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C01SW }, 0}, 236 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_USB305}, 0}, 237 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_TRUINSTALL }, DEV_TRUINSTALL}, 238 239 {{ USB_VENDOR_TCTMOBILE, USB_PRODUCT_TCTMOBILE_UMASS }, DEV_UMASS3}, 240 {{ USB_VENDOR_TCTMOBILE, USB_PRODUCT_TCTMOBILE_UMSM }, 0}, 241 242 {{ USB_VENDOR_TOSHIBA, USB_PRODUCT_TOSHIBA_HSDPA }, 0}, 243 244 {{ USB_VENDOR_HP, USB_PRODUCT_HP_HS2300 }, 0}, 245 246 {{ USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CNU510 }, 0}, /* ??? */ 247 {{ USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CCU550 }, 0}, /* ??? */ 248 {{ USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CGU628 }, DEV_UMASS1}, 249 {{ USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CGU628_DISK }, 0}, 250 {{ USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CNU680 }, DEV_UMASS1}, 251 }; 252 253 #define umsm_lookup(v, p) ((const struct umsm_type *)usb_lookup(umsm_devs, v, p)) 254 255 struct cfdriver umsm_cd = { 256 NULL, "umsm", DV_DULL 257 }; 258 259 const struct cfattach umsm_ca = { 260 sizeof(struct umsm_softc), 261 umsm_match, 262 umsm_attach, 263 umsm_detach, 264 umsm_activate, 265 }; 266 267 int 268 umsm_match(struct device *parent, void *match, void *aux) 269 { 270 struct usb_attach_arg *uaa = aux; 271 usb_interface_descriptor_t *id; 272 uint16_t flag; 273 274 if (uaa->iface == NULL) 275 return UMATCH_NONE; 276 277 /* 278 * Some devices (eg Huawei E220) have multiple interfaces and some 279 * of them are of class umass. Don't claim ownership in such case. 280 */ 281 if (umsm_lookup(uaa->vendor, uaa->product) != NULL) { 282 id = usbd_get_interface_descriptor(uaa->iface); 283 flag = umsm_lookup(uaa->vendor, uaa->product)->umsm_flag; 284 285 if (id == NULL || id->bInterfaceClass == UICLASS_MASS) { 286 /* 287 * Some high-speed modems require special care. 288 */ 289 if (flag & DEV_HUAWEI) { 290 if (uaa->ifaceno != 2) 291 return UMATCH_VENDOR_IFACESUBCLASS; 292 else 293 return UMATCH_NONE; 294 } else if (flag & DEV_UMASS) { 295 return UMATCH_VENDOR_IFACESUBCLASS; 296 } else if (flag & DEV_TRUINSTALL) { 297 return UMATCH_VENDOR_IFACESUBCLASS; 298 } else 299 return UMATCH_NONE; 300 } else 301 return UMATCH_VENDOR_IFACESUBCLASS; 302 } 303 304 return UMATCH_NONE; 305 } 306 307 void 308 umsm_attach(struct device *parent, struct device *self, void *aux) 309 { 310 struct umsm_softc *sc = (struct umsm_softc *)self; 311 struct usb_attach_arg *uaa = aux; 312 struct ucom_attach_args uca; 313 usb_interface_descriptor_t *id; 314 usb_endpoint_descriptor_t *ed; 315 int i; 316 317 bzero(&uca, sizeof(uca)); 318 sc->sc_udev = uaa->device; 319 sc->sc_iface = uaa->iface; 320 sc->sc_flag = umsm_lookup(uaa->vendor, uaa->product)->umsm_flag; 321 322 id = usbd_get_interface_descriptor(sc->sc_iface); 323 324 /* 325 * Some 3G modems have multiple interfaces and some of them 326 * are umass class. Don't claim ownership in such case. 327 */ 328 if (id == NULL || id->bInterfaceClass == UICLASS_MASS) { 329 /* 330 * Some 3G modems require a special request to 331 * enable their modem function. 332 */ 333 if ((sc->sc_flag & DEV_HUAWEI) && uaa->ifaceno == 0) { 334 umsm_huawei_changemode(uaa->device); 335 printf("%s: umass only mode. need to reattach\n", 336 sc->sc_dev.dv_xname); 337 } else if ((sc->sc_flag & DEV_TRUINSTALL) && 338 uaa->ifaceno == 0) { 339 umsm_truinstall_changemode(uaa->device); 340 printf("%s: truinstall mode. need to reattach\n", 341 sc->sc_dev.dv_xname); 342 } else if ((sc->sc_flag & DEV_UMASS) && uaa->ifaceno == 0) { 343 umsm_umass_changemode(sc); 344 } 345 346 /* 347 * The device will reset its own bus from the device side 348 * when its mode was changed, so just return. 349 */ 350 return; 351 } 352 353 sc->sc_iface_no = id->bInterfaceNumber; 354 uca.bulkin = uca.bulkout = -1; 355 sc->sc_intr_number = sc->sc_isize = -1; 356 for (i = 0; i < id->bNumEndpoints; i++) { 357 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 358 if (ed == NULL) { 359 printf("%s: no endpoint descriptor found for %d\n", 360 sc->sc_dev.dv_xname, i); 361 sc->sc_dying = 1; 362 return; 363 } 364 365 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 366 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 367 sc->sc_intr_number = ed->bEndpointAddress; 368 sc->sc_isize = UGETW(ed->wMaxPacketSize); 369 DPRINTF(("%s: find interrupt endpoint for %s\n", 370 __func__, sc->sc_dev.dv_xname)); 371 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 372 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 373 uca.bulkin = ed->bEndpointAddress; 374 else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 375 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 376 uca.bulkout = ed->bEndpointAddress; 377 } 378 if (uca.bulkin == -1 || uca.bulkout == -1) { 379 printf("%s: missing endpoint\n", sc->sc_dev.dv_xname); 380 sc->sc_dying = 1; 381 return; 382 } 383 384 sc->sc_dtr = sc->sc_rts = -1; 385 386 /* We need to force size as some devices lie */ 387 uca.ibufsize = UMSMBUFSZ; 388 uca.obufsize = UMSMBUFSZ; 389 uca.ibufsizepad = UMSMBUFSZ; 390 uca.opkthdrlen = 0; 391 uca.device = sc->sc_udev; 392 uca.iface = sc->sc_iface; 393 uca.methods = &umsm_methods; 394 uca.arg = sc; 395 uca.info = NULL; 396 uca.portno = UCOM_UNK_PORTNO; 397 398 sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); 399 } 400 401 int 402 umsm_detach(struct device *self, int flags) 403 { 404 struct umsm_softc *sc = (struct umsm_softc *)self; 405 int rv = 0; 406 407 /* close the interrupt endpoint if that is opened */ 408 if (sc->sc_intr_pipe != NULL) { 409 usbd_abort_pipe(sc->sc_intr_pipe); 410 usbd_close_pipe(sc->sc_intr_pipe); 411 free(sc->sc_intr_buf, M_USBDEV); 412 sc->sc_intr_pipe = NULL; 413 } 414 415 sc->sc_dying = 1; 416 if (sc->sc_subdev != NULL) { 417 rv = config_detach(sc->sc_subdev, flags); 418 sc->sc_subdev = NULL; 419 } 420 421 return (rv); 422 } 423 424 int 425 umsm_activate(struct device *self, int act) 426 { 427 struct umsm_softc *sc = (struct umsm_softc *)self; 428 int rv = 0; 429 430 switch (act) { 431 case DVACT_DEACTIVATE: 432 if (sc->sc_subdev != NULL) 433 rv = config_deactivate(sc->sc_subdev); 434 sc->sc_dying = 1; 435 break; 436 } 437 return (rv); 438 } 439 440 int 441 umsm_open(void *addr, int portno) 442 { 443 struct umsm_softc *sc = addr; 444 int err; 445 446 if (sc->sc_dying) 447 return (ENXIO); 448 449 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { 450 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 451 err = usbd_open_pipe_intr(sc->sc_iface, 452 sc->sc_intr_number, 453 USBD_SHORT_XFER_OK, 454 &sc->sc_intr_pipe, 455 sc, 456 sc->sc_intr_buf, 457 sc->sc_isize, 458 umsm_intr, 459 UMSM_INTR_INTERVAL); 460 if (err) { 461 printf("%s: cannot open interrupt pipe (addr %d)\n", 462 sc->sc_dev.dv_xname, 463 sc->sc_intr_number); 464 return (EIO); 465 } 466 } 467 468 return (0); 469 } 470 471 void 472 umsm_close(void *addr, int portno) 473 { 474 struct umsm_softc *sc = addr; 475 int err; 476 477 if (sc->sc_dying) 478 return; 479 480 if (sc->sc_intr_pipe != NULL) { 481 err = usbd_abort_pipe(sc->sc_intr_pipe); 482 if (err) 483 printf("%s: abort interrupt pipe failed: %s\n", 484 sc->sc_dev.dv_xname, 485 usbd_errstr(err)); 486 err = usbd_close_pipe(sc->sc_intr_pipe); 487 if (err) 488 printf("%s: close interrupt pipe failed: %s\n", 489 sc->sc_dev.dv_xname, 490 usbd_errstr(err)); 491 free(sc->sc_intr_buf, M_USBDEV); 492 sc->sc_intr_pipe = NULL; 493 } 494 } 495 496 void 497 umsm_intr(usbd_xfer_handle xfer, usbd_private_handle priv, 498 usbd_status status) 499 { 500 struct umsm_softc *sc = priv; 501 usb_cdc_notification_t *buf; 502 u_char mstatus; 503 504 buf = (usb_cdc_notification_t *)sc->sc_intr_buf; 505 if (sc->sc_dying) 506 return; 507 508 if (status != USBD_NORMAL_COMPLETION) { 509 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 510 return; 511 512 DPRINTF(("%s: umsm_intr: abnormal status: %s\n", 513 sc->sc_dev.dv_xname, usbd_errstr(status))); 514 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 515 return; 516 } 517 518 if (buf->bmRequestType != UCDC_NOTIFICATION) { 519 #if 1 /* test */ 520 printf("%s: this device is not using CDC notify message in intr pipe.\n" 521 "Please send your dmesg to <bugs@openbsd.org>, thanks.\n", 522 sc->sc_dev.dv_xname); 523 printf("%s: intr buffer 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", 524 sc->sc_dev.dv_xname, 525 sc->sc_intr_buf[0], sc->sc_intr_buf[1], 526 sc->sc_intr_buf[2], sc->sc_intr_buf[3], 527 sc->sc_intr_buf[4], sc->sc_intr_buf[5], 528 sc->sc_intr_buf[6]); 529 #else 530 DPRINTF(("%s: umsm_intr: unknown message type(0x%02x)\n", 531 sc->sc_dev.dv_xname, buf->bmRequestType)); 532 #endif 533 return; 534 } 535 536 if (buf->bNotification == UCDC_N_SERIAL_STATE) { 537 /* invalid message length, discard it */ 538 if (UGETW(buf->wLength) != 2) 539 return; 540 /* XXX: sc_lsr is always 0 */ 541 sc->sc_lsr = sc->sc_msr = 0; 542 mstatus = buf->data[0]; 543 if (ISSET(mstatus, UCDC_N_SERIAL_RI)) 544 sc->sc_msr |= UMSR_RI; 545 if (ISSET(mstatus, UCDC_N_SERIAL_DSR)) 546 sc->sc_msr |= UMSR_DSR; 547 if (ISSET(mstatus, UCDC_N_SERIAL_DCD)) 548 sc->sc_msr |= UMSR_DCD; 549 } else if (buf->bNotification != UCDC_N_CONNECTION_SPEED_CHANGE) { 550 DPRINTF(("%s: umsm_intr: unknown notify message (0x%02x)\n", 551 sc->sc_dev.dv_xname, buf->bNotification)); 552 return; 553 } 554 555 ucom_status_change((struct ucom_softc *)sc->sc_subdev); 556 } 557 558 void 559 umsm_get_status(void *addr, int portno, u_char *lsr, u_char *msr) 560 { 561 struct umsm_softc *sc = addr; 562 563 if (lsr != NULL) 564 *lsr = sc->sc_lsr; 565 if (msr != NULL) 566 *msr = sc->sc_msr; 567 } 568 569 void 570 umsm_set(void *addr, int portno, int reg, int onoff) 571 { 572 struct umsm_softc *sc = addr; 573 usb_device_request_t req; 574 int ls; 575 576 switch (reg) { 577 case UCOM_SET_DTR: 578 if (sc->sc_dtr == onoff) 579 return; 580 sc->sc_dtr = onoff; 581 break; 582 case UCOM_SET_RTS: 583 if (sc->sc_rts == onoff) 584 return; 585 sc->sc_rts = onoff; 586 break; 587 default: 588 return; 589 } 590 591 /* build a usb request */ 592 ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) | 593 (sc->sc_rts ? UCDC_LINE_RTS : 0); 594 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 595 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 596 USETW(req.wValue, ls); 597 USETW(req.wIndex, sc->sc_iface_no); 598 USETW(req.wLength, 0); 599 600 (void)usbd_do_request(sc->sc_udev, &req, 0); 601 } 602 603 usbd_status 604 umsm_huawei_changemode(usbd_device_handle dev) 605 { 606 usb_device_request_t req; 607 usbd_status err; 608 609 req.bmRequestType = UT_WRITE_DEVICE; 610 req.bRequest = UR_SET_FEATURE; 611 USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); 612 USETW(req.wIndex, E220_MODE_CHANGE_REQUEST); 613 USETW(req.wLength, 0); 614 615 err = usbd_do_request(dev, &req, 0); 616 if (err) 617 return (EIO); 618 619 return (0); 620 } 621 622 usbd_status 623 umsm_truinstall_changemode(usbd_device_handle dev) 624 { 625 usb_device_request_t req; 626 usbd_status err; 627 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 628 req.bRequest = TRUINSTALL_CHANGEMODE_REQUEST; 629 USETW(req.wValue, 0x1); 630 USETW(req.wIndex, 0); 631 USETW(req.wLength, 0); 632 633 err = usbd_do_request(dev, &req, 0); 634 if (err) 635 return (EIO); 636 637 return (0); 638 } 639 640 usbd_status 641 umsm_umass_changemode(struct umsm_softc *sc) 642 { 643 #define UMASS_CMD_REZERO_UNIT 0x01 644 #define UMASS_CMD_START_STOP 0x1b 645 #define UMASS_CMDPARAM_EJECT 0x02 646 #define UMASS_SERVICE_ACTION_OUT 0x9f 647 usb_interface_descriptor_t *id; 648 usb_endpoint_descriptor_t *ed; 649 usbd_xfer_handle xfer; 650 usbd_pipe_handle cmdpipe; 651 usbd_status err; 652 u_int32_t n; 653 void *bufp; 654 int target_ep, i; 655 656 umass_bbb_cbw_t cbw; 657 static int dCBWTag = 0x12345678; 658 659 USETDW(cbw.dCBWSignature, CBWSIGNATURE); 660 USETDW(cbw.dCBWTag, dCBWTag); 661 cbw.bCBWLUN = 0; 662 cbw.bCDBLength= 6; 663 bzero(cbw.CBWCDB, sizeof(cbw.CBWCDB)); 664 665 switch (sc->sc_flag) { 666 case DEV_UMASS1: 667 USETDW(cbw.dCBWDataTransferLength, 0x0); 668 cbw.bCBWFlags = CBWFLAGS_OUT; 669 cbw.CBWCDB[0] = UMASS_CMD_REZERO_UNIT; 670 cbw.CBWCDB[1] = 0x0; /* target LUN: 0 */ 671 break; 672 case DEV_UMASS2: 673 USETDW(cbw.dCBWDataTransferLength, 0x1); 674 cbw.bCBWFlags = CBWFLAGS_IN; 675 cbw.CBWCDB[0] = UMASS_CMD_REZERO_UNIT; 676 cbw.CBWCDB[1] = 0x0; /* target LUN: 0 */ 677 break; 678 case DEV_UMASS3: /* longcheer */ 679 USETDW(cbw.dCBWDataTransferLength, 0x80); 680 cbw.bCBWFlags = CBWFLAGS_IN; 681 cbw.CBWCDB[0] = 0x06; 682 cbw.CBWCDB[1] = 0xf5; 683 cbw.CBWCDB[2] = 0x04; 684 cbw.CBWCDB[3] = 0x02; 685 cbw.CBWCDB[4] = 0x52; 686 cbw.CBWCDB[5] = 0x70; 687 break; 688 case DEV_UMASS4: 689 USETDW(cbw.dCBWDataTransferLength, 0x0); 690 cbw.bCBWFlags = CBWFLAGS_OUT; 691 cbw.CBWCDB[0] = UMASS_CMD_START_STOP; 692 cbw.CBWCDB[1] = 0x00; /* target LUN: 0 */ 693 cbw.CBWCDB[4] = UMASS_CMDPARAM_EJECT; 694 break; 695 case DEV_UMASS5: 696 cbw.bCBWFlags = CBWFLAGS_OUT; 697 cbw.CBWCDB[0] = 0x11; 698 cbw.CBWCDB[1] = 0x06; 699 break; 700 case DEV_UMASS6: /* ZTE */ 701 USETDW(cbw.dCBWDataTransferLength, 0x20); 702 cbw.bCBWFlags = CBWFLAGS_IN; 703 cbw.bCDBLength= 12; 704 cbw.CBWCDB[0] = 0x85; 705 cbw.CBWCDB[1] = 0x01; 706 cbw.CBWCDB[2] = 0x01; 707 cbw.CBWCDB[3] = 0x01; 708 cbw.CBWCDB[4] = 0x18; 709 cbw.CBWCDB[5] = 0x01; 710 cbw.CBWCDB[6] = 0x01; 711 cbw.CBWCDB[7] = 0x01; 712 cbw.CBWCDB[8] = 0x01; 713 cbw.CBWCDB[9] = 0x01; 714 break; 715 case DEV_UMASS7: /* ZTE */ 716 USETDW(cbw.dCBWDataTransferLength, 0xc0); 717 cbw.bCBWFlags = CBWFLAGS_IN; 718 cbw.CBWCDB[0] = UMASS_SERVICE_ACTION_OUT; 719 cbw.CBWCDB[1] = 0x03; 720 break; 721 default: 722 DPRINTF(("%s: unknown device type.\n", sc->sc_dev.dv_xname)); 723 break; 724 } 725 726 /* get command endpoint address */ 727 id = usbd_get_interface_descriptor(sc->sc_iface); 728 for (i = 0; i < id->bNumEndpoints; i++) { 729 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 730 if (ed == NULL) { 731 return (USBD_IOERROR); 732 } 733 734 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 735 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 736 target_ep = ed->bEndpointAddress; 737 } 738 739 /* open command endppoint */ 740 err = usbd_open_pipe(sc->sc_iface, target_ep, 741 USBD_EXCLUSIVE_USE, &cmdpipe); 742 if (err) { 743 DPRINTF(("%s: open pipe for modem change cmd failed: %s\n", 744 sc->sc_dev.dv_xname, usbd_errstr(err))); 745 return (err); 746 } 747 748 xfer = usbd_alloc_xfer(sc->sc_udev); 749 if (xfer == NULL) { 750 usbd_close_pipe(cmdpipe); 751 return (USBD_NOMEM); 752 } else { 753 bufp = usbd_alloc_buffer(xfer, UMASS_BBB_CBW_SIZE); 754 if (bufp == NULL) 755 err = USBD_NOMEM; 756 else { 757 n = UMASS_BBB_CBW_SIZE; 758 memcpy(bufp, &cbw, UMASS_BBB_CBW_SIZE); 759 err = usbd_bulk_transfer(xfer, cmdpipe, USBD_NO_COPY, 760 USBD_NO_TIMEOUT, bufp, &n, "umsm"); 761 if (err) 762 DPRINTF(("%s: send error:%s", __func__, 763 usbd_errstr(err))); 764 } 765 usbd_close_pipe(cmdpipe); 766 usbd_free_buffer(xfer); 767 usbd_free_xfer(xfer); 768 } 769 770 return (err); 771 } 772