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