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