| File: | dev/usb/umsm.c |
| Warning: | line 788, column 8 2nd function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: umsm.c,v 1.125 2023/04/02 23:57:57 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/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/usbdevs.h> | |||
| 33 | #include <dev/usb/ucomvar.h> | |||
| 34 | #include <dev/usb/usbcdc.h> | |||
| 35 | #include <dev/usb/umassvar.h> | |||
| 36 | #undef DPRINTF /* undef DPRINTF for umass */ | |||
| 37 | ||||
| 38 | #ifdef UMSM_DEBUG | |||
| 39 | int umsmdebug = 0; | |||
| 40 | #define DPRINTFN(n, x) do { if (umsmdebug > (n)) printf x; } while (0) | |||
| 41 | #else | |||
| 42 | #define DPRINTFN(n, x) | |||
| 43 | #endif | |||
| 44 | ||||
| 45 | #define DPRINTF(x) DPRINTFN(0, x) | |||
| 46 | ||||
| 47 | #define UMSMBUFSZ4096 4096 | |||
| 48 | #define UMSM_INTR_INTERVAL100 100 /* ms */ | |||
| 49 | #define E220_MODE_CHANGE_REQUEST0x2 0x2 | |||
| 50 | #define TRUINSTALL_CHANGEMODE_REQUEST0x0b 0x0b | |||
| 51 | ||||
| 52 | int umsm_match(struct device *, void *, void *); | |||
| 53 | void umsm_attach(struct device *, struct device *, void *); | |||
| 54 | int umsm_detach(struct device *, int); | |||
| 55 | ||||
| 56 | int umsm_open(void *, int); | |||
| 57 | void umsm_close(void *, int); | |||
| 58 | void umsm_intr(struct usbd_xfer *, void *, usbd_status); | |||
| 59 | void umsm_get_status(void *, int, u_char *, u_char *); | |||
| 60 | void umsm_set(void *, int, int, int); | |||
| 61 | ||||
| 62 | struct umsm_softc { | |||
| 63 | struct device sc_dev; | |||
| 64 | struct usbd_device *sc_udev; | |||
| 65 | struct usbd_interface *sc_iface; | |||
| 66 | int sc_iface_no; | |||
| 67 | struct device *sc_subdev; | |||
| 68 | uint16_t sc_flag; | |||
| 69 | ||||
| 70 | /* interrupt ep */ | |||
| 71 | int sc_intr_number; | |||
| 72 | struct usbd_pipe *sc_intr_pipe; | |||
| 73 | u_char *sc_intr_buf; | |||
| 74 | int sc_isize; | |||
| 75 | ||||
| 76 | u_char sc_lsr; /* Local status register */ | |||
| 77 | u_char sc_msr; /* status register */ | |||
| 78 | u_char sc_dtr; /* current DTR state */ | |||
| 79 | u_char sc_rts; /* current RTS state */ | |||
| 80 | }; | |||
| 81 | ||||
| 82 | usbd_status umsm_huawei_changemode(struct usbd_device *); | |||
| 83 | usbd_status umsm_truinstall_changemode(struct usbd_device *); | |||
| 84 | usbd_status umsm_umass_changemode(struct umsm_softc *); | |||
| 85 | ||||
| 86 | const struct ucom_methods umsm_methods = { | |||
| 87 | umsm_get_status, | |||
| 88 | umsm_set, | |||
| 89 | NULL((void *)0), | |||
| 90 | NULL((void *)0), | |||
| 91 | umsm_open, | |||
| 92 | umsm_close, | |||
| 93 | NULL((void *)0), | |||
| 94 | NULL((void *)0), | |||
| 95 | }; | |||
| 96 | ||||
| 97 | struct umsm_type { | |||
| 98 | struct usb_devno umsm_dev; | |||
| 99 | uint16_t umsm_flag; | |||
| 100 | /* device type */ | |||
| 101 | #define DEV_NORMAL0x0000 0x0000 | |||
| 102 | #define DEV_HUAWEI0x0001 0x0001 | |||
| 103 | #define DEV_TRUINSTALL0x0002 0x0002 | |||
| 104 | #define DEV_UMASS10x0010 0x0010 | |||
| 105 | #define DEV_UMASS20x0020 0x0020 | |||
| 106 | #define DEV_UMASS30x0040 0x0040 | |||
| 107 | #define DEV_UMASS40x0080 0x0080 | |||
| 108 | #define DEV_UMASS50x0100 0x0100 | |||
| 109 | #define DEV_UMASS60x0200 0x0200 | |||
| 110 | #define DEV_UMASS70x0400 0x0400 | |||
| 111 | #define DEV_UMASS80x1000 0x1000 | |||
| 112 | #define DEV_UMASS(0x0010 | 0x0020 | 0x0040 | 0x0080 | 0x0100 | 0x0200 | 0x0400 | 0x1000) (DEV_UMASS10x0010 | DEV_UMASS20x0020 | DEV_UMASS30x0040 | DEV_UMASS40x0080 | \ | |||
| 113 | DEV_UMASS50x0100 | DEV_UMASS60x0200 | DEV_UMASS70x0400 | DEV_UMASS80x1000) | |||
| 114 | }; | |||
| 115 | ||||
| 116 | static const struct umsm_type umsm_devs[] = { | |||
| 117 | {{ USB_VENDOR_AIRPRIME0x0f3d, USB_PRODUCT_AIRPRIME_PC52200x0112 }, 0}, | |||
| 118 | {{ USB_VENDOR_AIRPRIME0x0f3d, USB_PRODUCT_AIRPRIME_AIRCARD_313U0x68aa }, 0}, | |||
| 119 | ||||
| 120 | {{ USB_VENDOR_ANYDATA0x16d5, USB_PRODUCT_ANYDATA_A25020x6202 }, 0}, | |||
| 121 | {{ USB_VENDOR_ANYDATA0x16d5, USB_PRODUCT_ANYDATA_ADU_500A0x6502 }, 0}, | |||
| 122 | {{ USB_VENDOR_ANYDATA0x16d5, USB_PRODUCT_ANYDATA_ADU_E100H0x6501 }, 0}, | |||
| 123 | ||||
| 124 | {{ USB_VENDOR_DELL0x413c, USB_PRODUCT_DELL_EU870D0x8138 }, 0}, | |||
| 125 | {{ USB_VENDOR_DELL0x413c, USB_PRODUCT_DELL_U7400x8135 }, 0}, | |||
| 126 | {{ USB_VENDOR_DELL0x413c, USB_PRODUCT_DELL_W55000x8115 }, 0}, | |||
| 127 | ||||
| 128 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E1610x1446 }, DEV_UMASS50x0100}, | |||
| 129 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E173S_INIT0x1c0b }, DEV_UMASS50x0100}, | |||
| 130 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E173S0x1c05 }, 0}, | |||
| 131 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E1800x140c }, DEV_HUAWEI0x0001}, | |||
| 132 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E1810x1414 }, DEV_HUAWEI0x0001}, | |||
| 133 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E1820x1429 }, DEV_UMASS50x0100}, | |||
| 134 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E18200x14ac }, DEV_UMASS50x0100}, | |||
| 135 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E2200x1003 }, DEV_HUAWEI0x0001}, | |||
| 136 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E3030x1f01 }, DEV_UMASS50x0100}, | |||
| 137 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E353_INIT0x14fe }, DEV_UMASS50x0100}, | |||
| 138 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E5100x1411 }, DEV_HUAWEI0x0001}, | |||
| 139 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E6180x1001 }, DEV_HUAWEI0x0001}, | |||
| 140 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E392_INIT0x1505 }, DEV_UMASS50x0100}, | |||
| 141 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_EM770W0x1404 }, 0}, | |||
| 142 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_MOBILE0x1008 }, DEV_HUAWEI0x0001}, | |||
| 143 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_K3765_INIT0x1520 }, DEV_UMASS50x0100}, | |||
| 144 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_K37650x1465 }, 0}, | |||
| 145 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_K3772_INIT0x1526 }, DEV_UMASS50x0100}, | |||
| 146 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_K37720x14cf }, 0}, | |||
| 147 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_MU6090x1573 }, DEV_TRUINSTALL0x0002}, | |||
| 148 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_K45100x14c5 }, DEV_UMASS50x0100}, | |||
| 149 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_K45110x14b7 }, DEV_UMASS50x0100}, | |||
| 150 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E17500x1406 }, DEV_UMASS50x0100}, | |||
| 151 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E17520x1417 }, 0}, | |||
| 152 | {{ USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_E33720x1442 }, DEV_UMASS50x0100}, | |||
| 153 | ||||
| 154 | {{ USB_VENDOR_HYUNDAI0x106c, USB_PRODUCT_HYUNDAI_UM1750x3714 }, 0}, | |||
| 155 | ||||
| 156 | {{ USB_VENDOR_LONGCHEER0x1c9e, USB_PRODUCT_LONGCHEER_D21LCMASS0x9401 }, DEV_UMASS30x0040}, | |||
| 157 | {{ USB_VENDOR_LONGCHEER0x1c9e, USB_PRODUCT_LONGCHEER_D21LC0x9404 }, 0}, | |||
| 158 | {{ USB_VENDOR_LONGCHEER0x1c9e, USB_PRODUCT_LONGCHEER_510FUMASS0x98ff }, DEV_UMASS30x0040}, | |||
| 159 | {{ USB_VENDOR_LONGCHEER0x1c9e, USB_PRODUCT_LONGCHEER_510FU0x9801 }, 0}, | |||
| 160 | ||||
| 161 | {{ USB_VENDOR_KYOCERA20x0c88, USB_PRODUCT_KYOCERA2_KPC6500x17da }, 0}, | |||
| 162 | ||||
| 163 | {{ USB_VENDOR_MEDIATEK0x0e8d, USB_PRODUCT_MEDIATEK_UMASS0x0002 }, DEV_UMASS80x1000}, | |||
| 164 | {{ USB_VENDOR_MEDIATEK0x0e8d, USB_PRODUCT_MEDIATEK_DC_4COM0x00a5 }, 0}, | |||
| 165 | ||||
| 166 | /* XXX Some qualcomm devices are missing */ | |||
| 167 | {{ USB_VENDOR_QUALCOMM0x05c6, USB_PRODUCT_QUALCOMM_MSM_DRIVER0x1000 }, DEV_UMASS10x0010}, | |||
| 168 | {{ USB_VENDOR_QUALCOMM0x05c6, USB_PRODUCT_QUALCOMM_MSM_DRIVER20xf000 }, DEV_UMASS40x0080}, | |||
| 169 | {{ USB_VENDOR_QUALCOMM0x05c6, USB_PRODUCT_QUALCOMM_MSM_HSDPA0x6613 }, 0}, | |||
| 170 | {{ USB_VENDOR_QUALCOMM0x05c6, USB_PRODUCT_QUALCOMM_MSM_HSDPA20x6000 }, 0}, | |||
| 171 | {{ USB_VENDOR_QUALCOMM0x05c6, USB_PRODUCT_QUALCOMM_MSM_HSDPA30x9000 }, 0}, | |||
| 172 | ||||
| 173 | {{ USB_VENDOR_QUANTA20x0408, USB_PRODUCT_QUANTA2_UMASS0x1000 }, DEV_UMASS40x0080}, | |||
| 174 | {{ USB_VENDOR_QUANTA20x0408, USB_PRODUCT_QUANTA2_Q1010xea02 }, 0}, | |||
| 175 | ||||
| 176 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_EC210x0121 }, 0}, | |||
| 177 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_EC250x0125 }, 0}, | |||
| 178 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_EG910x0191 }, 0}, | |||
| 179 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_EG950x0195 }, 0}, | |||
| 180 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_BG960x0296 }, 0}, | |||
| 181 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_EG060x0306 }, 0}, | |||
| 182 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_AG150x0415 }, 0}, | |||
| 183 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_AG350x0435 }, 0}, | |||
| 184 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_AG520R0x0452 }, 0}, | |||
| 185 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_AG525R0x0455 }, 0}, | |||
| 186 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_EG120x0512 }, 0}, | |||
| 187 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_EG200x0620 }, 0}, | |||
| 188 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_BG950x0700 }, 0}, | |||
| 189 | {{ USB_VENDOR_QUECTEL0x2c7c, USB_PRODUCT_QUECTEL_RG5XXQ0x0800 }, 0}, | |||
| 190 | ||||
| 191 | {{ USB_VENDOR_ZTE0x19d2, USB_PRODUCT_ZTE_AC27460xfff1 }, 0}, | |||
| 192 | {{ USB_VENDOR_ZTE0x19d2, USB_PRODUCT_ZTE_UMASS_INSTALLER0x2000 }, DEV_UMASS40x0080}, | |||
| 193 | {{ USB_VENDOR_ZTE0x19d2, USB_PRODUCT_ZTE_UMASS_INSTALLER20x0103 }, DEV_UMASS60x0200}, | |||
| 194 | {{ USB_VENDOR_ZTE0x19d2, USB_PRODUCT_ZTE_UMASS_INSTALLER30xfff5 }, DEV_UMASS70x0400}, | |||
| 195 | {{ USB_VENDOR_ZTE0x19d2, USB_PRODUCT_ZTE_UMASS_INSTALLER40x0083 }, DEV_UMASS40x0080}, | |||
| 196 | {{ USB_VENDOR_ZTE0x19d2, USB_PRODUCT_ZTE_K3565Z0x0063 }, 0}, | |||
| 197 | {{ USB_VENDOR_ZTE0x19d2, USB_PRODUCT_ZTE_MF1120x0117 }, DEV_UMASS40x0080}, | |||
| 198 | {{ USB_VENDOR_ZTE0x19d2, USB_PRODUCT_ZTE_MF6330x0016 }, 0}, | |||
| 199 | {{ USB_VENDOR_ZTE0x19d2, USB_PRODUCT_ZTE_MF6370x0031 }, 0}, | |||
| 200 | {{ USB_VENDOR_ZTE0x19d2, USB_PRODUCT_ZTE_MSA110UP0x0091 }, 0}, | |||
| 201 | ||||
| 202 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_EXPRESSCARD0x1100 }, 0}, | |||
| 203 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_MERLINV6200x1110 }, 0}, | |||
| 204 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_MERLINV7400x1120 }, 0}, | |||
| 205 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_V7200x1130 }, 0}, | |||
| 206 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_MERLINU7400x1400 }, 0}, | |||
| 207 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_MERLINU740_20x1410 }, 0}, | |||
| 208 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_U8700x1420 }, 0}, | |||
| 209 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_XU8700x1430 }, 0}, | |||
| 210 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_EU870D0x2420 }, 0}, | |||
| 211 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_X950D0x1450 }, 0}, | |||
| 212 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_ES6200x2100 }, 0}, | |||
| 213 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_U7200x2110 }, 0}, | |||
| 214 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_U7270x4100 }, DEV_UMASS10x0010}, | |||
| 215 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_MC950D0x4400 }, 0}, | |||
| 216 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_MERLINX950D0x5010 }, DEV_UMASS40x0080}, | |||
| 217 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_ZEROCD20x5030 }, DEV_UMASS40x0080}, | |||
| 218 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_U7600x6000 }, DEV_UMASS40x0080}, | |||
| 219 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_MC7600x6002 }, 0}, | |||
| 220 | {{ USB_VENDOR_NOVATEL0x1410, USB_PRODUCT_NOVATEL_MC760CD0x5031 }, DEV_UMASS40x0080}, | |||
| 221 | ||||
| 222 | {{ USB_VENDOR_NOVATEL10x09d7, USB_PRODUCT_NOVATEL1_FLEXPACKGPS0x0100 }, 0}, | |||
| 223 | ||||
| 224 | {{ USB_VENDOR_NOKIA20x0421, USB_PRODUCT_NOKIA2_CS15UMASS0x0610 }, DEV_UMASS40x0080}, | |||
| 225 | {{ USB_VENDOR_NOKIA20x0421, USB_PRODUCT_NOKIA2_CS150x0612 }, 0}, | |||
| 226 | ||||
| 227 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_GT3GFUSION0x6000 }, 0}, | |||
| 228 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_GT3GPLUS0x6721 }, 0}, | |||
| 229 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_GT3GQUAD0x6300 }, 0}, | |||
| 230 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_GT3GQUADPLUS0x6600 }, 0}, | |||
| 231 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_GSICON720x6911 }, DEV_UMASS10x0010}, | |||
| 232 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_GTHSUPA380E0x7211 }, 0}, | |||
| 233 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_GTMAX360x6701 }, 0}, | |||
| 234 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_ICON2250x6971 }, DEV_UMASS20x0020}, | |||
| 235 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_ICON5050xd055 }, DEV_UMASS10x0010}, | |||
| 236 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_SCORPION0x6901 }, 0}, | |||
| 237 | {{ USB_VENDOR_OPTION0x0af0, USB_PRODUCT_OPTION_VODAFONEMC3G0x5000 }, 0}, | |||
| 238 | ||||
| 239 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_EM56250x0017 }, 0}, | |||
| 240 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC57200x0018 }, 0}, | |||
| 241 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AIRCARD_5950x0019 }, 0}, | |||
| 242 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC57250x0020 }, 0}, | |||
| 243 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AC597E0x0021 }, 0}, | |||
| 244 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_C5970x0023 }, 0}, | |||
| 245 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AC595U0x0120 }, 0}, | |||
| 246 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AIRCARD_5800x0112 }, 0}, | |||
| 247 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC5720_20x0218 }, 0}, | |||
| 248 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC5725_20x0220 }, 0}, | |||
| 249 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC8755_20x6802 }, 0}, | |||
| 250 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC87650x6803 }, 0}, | |||
| 251 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC87550x6804 }, 0}, | |||
| 252 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC87750x6812 }, 0}, | |||
| 253 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC8755_30x6813 }, 0}, | |||
| 254 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC8775_20x6815 }, 0}, | |||
| 255 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AIRCARD_8750x6820 }, 0}, | |||
| 256 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC87800x6832 }, 0}, | |||
| 257 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC87810x6833 }, 0}, | |||
| 258 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC87900x683c }, 0}, | |||
| 259 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AC8800x6850 }, 0}, | |||
| 260 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AC8810x6851 }, 0}, | |||
| 261 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AC880E0x6852 }, 0}, | |||
| 262 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AC881E0x6853 }, 0}, | |||
| 263 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AC880U0x6855 }, 0}, | |||
| 264 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AC881U0x6856 }, 0}, | |||
| 265 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AC885U0x6880 }, 0}, | |||
| 266 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_C01SW0x6890 }, 0}, | |||
| 267 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_USB3050x68a3}, 0}, | |||
| 268 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC73040x68c0}, 0}, | |||
| 269 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_TRUINSTALL0x0fff }, DEV_TRUINSTALL0x0002}, | |||
| 270 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC83550x9013}, 0}, | |||
| 271 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AIRCARD_340U0x9051}, 0}, | |||
| 272 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_AIRCARD_770S0x9053}, 0}, | |||
| 273 | {{ USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_MC74550x9071}, 0}, | |||
| 274 | ||||
| 275 | {{ USB_VENDOR_SIMCOM0x1e0e, USB_PRODUCT_SIMCOM_SIM53200x9000}, 0}, | |||
| 276 | {{ USB_VENDOR_SIMCOM0x1e0e, USB_PRODUCT_SIMCOM_SIM7600E0x9001}, 0}, | |||
| 277 | ||||
| 278 | {{ USB_VENDOR_TCTMOBILE0x1bbb, USB_PRODUCT_TCTMOBILE_UMASS0xf000 }, DEV_UMASS30x0040}, | |||
| 279 | {{ USB_VENDOR_TCTMOBILE0x1bbb, USB_PRODUCT_TCTMOBILE_UMASS_20xf017 }, DEV_UMASS30x0040}, | |||
| 280 | {{ USB_VENDOR_TCTMOBILE0x1bbb, USB_PRODUCT_TCTMOBILE_UMSM0x0000 }, 0}, | |||
| 281 | {{ USB_VENDOR_TCTMOBILE0x1bbb, USB_PRODUCT_TCTMOBILE_UMSM_20x0017 }, 0}, | |||
| 282 | {{ USB_VENDOR_TCTMOBILE0x1bbb, USB_PRODUCT_TCTMOBILE_UMSM_30x011e }, 0}, | |||
| 283 | ||||
| 284 | {{ USB_VENDOR_TOSHIBA0x0930, USB_PRODUCT_TOSHIBA_HSDPA0x1302 }, 0}, | |||
| 285 | ||||
| 286 | {{ USB_VENDOR_HP0x03f0, USB_PRODUCT_HP_HS23000x1e1d }, 0}, | |||
| 287 | ||||
| 288 | {{ USB_VENDOR_CMOTECH0x16d8, USB_PRODUCT_CMOTECH_CNU5100x5141 }, 0}, /* ??? */ | |||
| 289 | {{ USB_VENDOR_CMOTECH0x16d8, USB_PRODUCT_CMOTECH_CCU5500x5533 }, 0}, /* ??? */ | |||
| 290 | {{ USB_VENDOR_CMOTECH0x16d8, USB_PRODUCT_CMOTECH_CGU6280x6006 }, DEV_UMASS10x0010}, | |||
| 291 | {{ USB_VENDOR_CMOTECH0x16d8, USB_PRODUCT_CMOTECH_CGU628_DISK0xf000 }, 0}, | |||
| 292 | {{ USB_VENDOR_CMOTECH0x16d8, USB_PRODUCT_CMOTECH_CNU6800x6803 }, DEV_UMASS10x0010}, | |||
| 293 | }; | |||
| 294 | ||||
| 295 | #define umsm_lookup(v, p)((const struct umsm_type *)usbd_match_device((const struct usb_devno *)(umsm_devs), sizeof (umsm_devs) / sizeof ((umsm_devs)[0]), sizeof ((umsm_devs)[0]), (v), (p))) ((const struct umsm_type *)usb_lookup(umsm_devs, v, p)usbd_match_device((const struct usb_devno *)(umsm_devs), sizeof (umsm_devs) / sizeof ((umsm_devs)[0]), sizeof ((umsm_devs)[0 ]), (v), (p))) | |||
| 296 | ||||
| 297 | struct cfdriver umsm_cd = { | |||
| 298 | NULL((void *)0), "umsm", DV_DULL | |||
| 299 | }; | |||
| 300 | ||||
| 301 | const struct cfattach umsm_ca = { | |||
| 302 | sizeof(struct umsm_softc), umsm_match, umsm_attach, umsm_detach | |||
| 303 | }; | |||
| 304 | ||||
| 305 | int | |||
| 306 | umsm_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((void *)0)) | |||
| 314 | return UMATCH_NONE0; | |||
| 315 | ||||
| 316 | umsmt = umsm_lookup(uaa->vendor, uaa->product)((const struct umsm_type *)usbd_match_device((const struct usb_devno *)(umsm_devs), sizeof (umsm_devs) / sizeof ((umsm_devs)[0]), sizeof ((umsm_devs)[0]), (uaa->vendor), (uaa->product) )); | |||
| 317 | if (umsmt == NULL((void *)0)) | |||
| 318 | return UMATCH_NONE0; | |||
| 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((void *)0) || id->bInterfaceClass == UICLASS_MASS0x08) { | |||
| 329 | /* | |||
| 330 | * Some high-speed modems require special care. | |||
| 331 | */ | |||
| 332 | if (flag & DEV_HUAWEI0x0001) { | |||
| 333 | if (uaa->ifaceno != 2) | |||
| 334 | return UMATCH_VENDOR_IFACESUBCLASS6; | |||
| 335 | else | |||
| 336 | return UMATCH_NONE0; | |||
| 337 | } else if (flag & DEV_UMASS(0x0010 | 0x0020 | 0x0040 | 0x0080 | 0x0100 | 0x0200 | 0x0400 | 0x1000)) { | |||
| 338 | return UMATCH_VENDOR_IFACESUBCLASS6; | |||
| 339 | } else if (flag & DEV_TRUINSTALL0x0002) { | |||
| 340 | return UMATCH_VENDOR_IFACESUBCLASS6; | |||
| 341 | } else | |||
| 342 | return UMATCH_NONE0; | |||
| 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_MEDIATEK0x0e8d && | |||
| 349 | uaa->product == USB_PRODUCT_MEDIATEK_DC_4COM0x00a5) && | |||
| 350 | !(id->bInterfaceClass == UICLASS_VENDOR0xff && | |||
| 351 | ((id->bInterfaceSubClass == 0x02 && | |||
| 352 | id->bInterfaceProtocol == 0x01) || | |||
| 353 | (id->bInterfaceSubClass == 0x00 && | |||
| 354 | id->bInterfaceProtocol == 0x00)))) { | |||
| 355 | return UMATCH_NONE0; | |||
| 356 | ||||
| 357 | /* See the Quectel LTE&5G Linux USB Driver User Guide */ | |||
| 358 | } else if (uaa->vendor == USB_VENDOR_QUECTEL0x2c7c) { | |||
| 359 | /* Some interfaces can be used as network devices */ | |||
| 360 | if (id->bInterfaceClass != UICLASS_VENDOR0xff) | |||
| 361 | return UMATCH_NONE0; | |||
| 362 | ||||
| 363 | /* Interface 4 can be used as a network device */ | |||
| 364 | if (uaa->ifaceno >= 4) | |||
| 365 | return UMATCH_NONE0; | |||
| 366 | } | |||
| 367 | ||||
| 368 | return UMATCH_VENDOR_IFACESUBCLASS6; | |||
| 369 | } | |||
| 370 | ||||
| 371 | void | |||
| 372 | umsm_attach(struct device *parent, struct device *self, void *aux) | |||
| 373 | { | |||
| 374 | struct umsm_softc *sc = (struct umsm_softc *)self; | |||
| 375 | struct usb_attach_arg *uaa = aux; | |||
| 376 | struct ucom_attach_args uca; | |||
| 377 | usb_interface_descriptor_t *id; | |||
| 378 | usb_endpoint_descriptor_t *ed; | |||
| 379 | int i; | |||
| 380 | ||||
| 381 | bzero(&uca, sizeof(uca))__builtin_bzero((&uca), (sizeof(uca))); | |||
| 382 | sc->sc_udev = uaa->device; | |||
| 383 | sc->sc_iface = uaa->iface; | |||
| 384 | sc->sc_flag = umsm_lookup(uaa->vendor, uaa->product)((const struct umsm_type *)usbd_match_device((const struct usb_devno *)(umsm_devs), sizeof (umsm_devs) / sizeof ((umsm_devs)[0]), sizeof ((umsm_devs)[0]), (uaa->vendor), (uaa->product) ))->umsm_flag; | |||
| 385 | ||||
| 386 | id = usbd_get_interface_descriptor(sc->sc_iface); | |||
| 387 | ||||
| 388 | /* | |||
| 389 | * Some 3G modems have multiple interfaces and some of them | |||
| 390 | * are umass class. Don't claim ownership in such case. | |||
| 391 | */ | |||
| 392 | if (id == NULL((void *)0) || id->bInterfaceClass == UICLASS_MASS0x08) { | |||
| ||||
| 393 | /* | |||
| 394 | * Some 3G modems require a special request to | |||
| 395 | * enable their modem function. | |||
| 396 | */ | |||
| 397 | if ((sc->sc_flag & DEV_HUAWEI0x0001) && uaa->ifaceno == 0) { | |||
| 398 | umsm_huawei_changemode(uaa->device); | |||
| 399 | printf("%s: umass only mode. need to reattach\n", | |||
| 400 | sc->sc_dev.dv_xname); | |||
| 401 | } else if (sc->sc_flag & DEV_TRUINSTALL0x0002) { | |||
| 402 | umsm_truinstall_changemode(uaa->device); | |||
| 403 | printf("%s: truinstall mode. need to reattach\n", | |||
| 404 | sc->sc_dev.dv_xname); | |||
| 405 | } else if ((sc->sc_flag & DEV_UMASS(0x0010 | 0x0020 | 0x0040 | 0x0080 | 0x0100 | 0x0200 | 0x0400 | 0x1000)) && uaa->ifaceno == 0) { | |||
| 406 | umsm_umass_changemode(sc); | |||
| 407 | } | |||
| 408 | ||||
| 409 | /* | |||
| 410 | * The device will reset its own bus from the device side | |||
| 411 | * when its mode was changed, so just return. | |||
| 412 | */ | |||
| 413 | return; | |||
| 414 | } | |||
| 415 | ||||
| 416 | sc->sc_iface_no = id->bInterfaceNumber; | |||
| 417 | uca.bulkin = uca.bulkout = -1; | |||
| 418 | sc->sc_intr_number = sc->sc_isize = -1; | |||
| 419 | for (i = 0; i < id->bNumEndpoints; i++) { | |||
| 420 | ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); | |||
| 421 | if (ed == NULL((void *)0)) { | |||
| 422 | printf("%s: no endpoint descriptor found for %d\n", | |||
| 423 | sc->sc_dev.dv_xname, i); | |||
| 424 | usbd_deactivate(sc->sc_udev); | |||
| 425 | return; | |||
| 426 | } | |||
| 427 | ||||
| 428 | if (UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_IN0x80 && | |||
| 429 | UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_INTERRUPT0x03) { | |||
| 430 | sc->sc_intr_number = ed->bEndpointAddress; | |||
| 431 | sc->sc_isize = UGETW(ed->wMaxPacketSize)(*(u_int16_t *)(ed->wMaxPacketSize)); | |||
| 432 | DPRINTF(("%s: find interrupt endpoint for %s\n", | |||
| 433 | __func__, sc->sc_dev.dv_xname)); | |||
| 434 | } else if (UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_IN0x80 && | |||
| 435 | UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_BULK0x02) | |||
| 436 | uca.bulkin = ed->bEndpointAddress; | |||
| 437 | else if (UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_OUT0x00 && | |||
| 438 | UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_BULK0x02) | |||
| 439 | uca.bulkout = ed->bEndpointAddress; | |||
| 440 | } | |||
| 441 | if (uca.bulkin == -1 || uca.bulkout == -1) { | |||
| 442 | printf("%s: missing endpoint\n", sc->sc_dev.dv_xname); | |||
| 443 | usbd_deactivate(sc->sc_udev); | |||
| 444 | return; | |||
| 445 | } | |||
| 446 | ||||
| 447 | sc->sc_dtr = sc->sc_rts = -1; | |||
| 448 | ||||
| 449 | /* We need to force size as some devices lie */ | |||
| 450 | uca.ibufsize = UMSMBUFSZ4096; | |||
| 451 | uca.obufsize = UMSMBUFSZ4096; | |||
| 452 | uca.ibufsizepad = UMSMBUFSZ4096; | |||
| 453 | uca.opkthdrlen = 0; | |||
| 454 | uca.device = sc->sc_udev; | |||
| 455 | uca.iface = sc->sc_iface; | |||
| 456 | uca.methods = &umsm_methods; | |||
| 457 | uca.arg = sc; | |||
| 458 | uca.info = NULL((void *)0); | |||
| 459 | uca.portno = UCOM_UNK_PORTNO-1; | |||
| 460 | ||||
| 461 | sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); | |||
| 462 | } | |||
| 463 | ||||
| 464 | int | |||
| 465 | umsm_detach(struct device *self, int flags) | |||
| 466 | { | |||
| 467 | struct umsm_softc *sc = (struct umsm_softc *)self; | |||
| 468 | int rv = 0; | |||
| 469 | ||||
| 470 | /* close the interrupt endpoint if that is opened */ | |||
| 471 | if (sc->sc_intr_pipe != NULL((void *)0)) { | |||
| 472 | usbd_close_pipe(sc->sc_intr_pipe); | |||
| 473 | free(sc->sc_intr_buf, M_USBDEV102, sc->sc_isize); | |||
| 474 | sc->sc_intr_pipe = NULL((void *)0); | |||
| 475 | } | |||
| 476 | ||||
| 477 | usbd_deactivate(sc->sc_udev); | |||
| 478 | if (sc->sc_subdev != NULL((void *)0)) { | |||
| 479 | rv = config_detach(sc->sc_subdev, flags); | |||
| 480 | sc->sc_subdev = NULL((void *)0); | |||
| 481 | } | |||
| 482 | ||||
| 483 | return (rv); | |||
| 484 | } | |||
| 485 | ||||
| 486 | int | |||
| 487 | umsm_open(void *addr, int portno) | |||
| 488 | { | |||
| 489 | struct umsm_softc *sc = addr; | |||
| 490 | int err; | |||
| 491 | ||||
| 492 | if (usbd_is_dying(sc->sc_udev)) | |||
| 493 | return (ENXIO6); | |||
| 494 | ||||
| 495 | if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL((void *)0)) { | |||
| 496 | sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV102, M_WAITOK0x0001); | |||
| 497 | err = usbd_open_pipe_intr(sc->sc_iface, | |||
| 498 | sc->sc_intr_number, | |||
| 499 | USBD_SHORT_XFER_OK0x04, | |||
| 500 | &sc->sc_intr_pipe, | |||
| 501 | sc, | |||
| 502 | sc->sc_intr_buf, | |||
| 503 | sc->sc_isize, | |||
| 504 | umsm_intr, | |||
| 505 | UMSM_INTR_INTERVAL100); | |||
| 506 | if (err) { | |||
| 507 | printf("%s: cannot open interrupt pipe (addr %d)\n", | |||
| 508 | sc->sc_dev.dv_xname, | |||
| 509 | sc->sc_intr_number); | |||
| 510 | return (EIO5); | |||
| 511 | } | |||
| 512 | } | |||
| 513 | ||||
| 514 | return (0); | |||
| 515 | } | |||
| 516 | ||||
| 517 | void | |||
| 518 | umsm_close(void *addr, int portno) | |||
| 519 | { | |||
| 520 | struct umsm_softc *sc = addr; | |||
| 521 | int err; | |||
| 522 | ||||
| 523 | if (usbd_is_dying(sc->sc_udev)) | |||
| 524 | return; | |||
| 525 | ||||
| 526 | if (sc->sc_intr_pipe != NULL((void *)0)) { | |||
| 527 | err = usbd_close_pipe(sc->sc_intr_pipe); | |||
| 528 | if (err) | |||
| 529 | printf("%s: close interrupt pipe failed: %s\n", | |||
| 530 | sc->sc_dev.dv_xname, | |||
| 531 | usbd_errstr(err)); | |||
| 532 | free(sc->sc_intr_buf, M_USBDEV102, sc->sc_isize); | |||
| 533 | sc->sc_intr_pipe = NULL((void *)0); | |||
| 534 | } | |||
| 535 | } | |||
| 536 | ||||
| 537 | void | |||
| 538 | umsm_intr(struct usbd_xfer *xfer, void *priv, | |||
| 539 | usbd_status status) | |||
| 540 | { | |||
| 541 | struct umsm_softc *sc = priv; | |||
| 542 | struct usb_cdc_notification *buf; | |||
| 543 | u_char mstatus; | |||
| 544 | ||||
| 545 | buf = (struct usb_cdc_notification *)sc->sc_intr_buf; | |||
| 546 | if (usbd_is_dying(sc->sc_udev)) | |||
| 547 | return; | |||
| 548 | ||||
| 549 | if (status != USBD_NORMAL_COMPLETION) { | |||
| 550 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) | |||
| 551 | return; | |||
| 552 | ||||
| 553 | DPRINTF(("%s: umsm_intr: abnormal status: %s\n", | |||
| 554 | sc->sc_dev.dv_xname, usbd_errstr(status))); | |||
| 555 | usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); | |||
| 556 | return; | |||
| 557 | } | |||
| 558 | ||||
| 559 | if (buf->bmRequestType != UCDC_NOTIFICATION0xa1) { | |||
| 560 | #if 1 /* test */ | |||
| 561 | printf("%s: this device is not using CDC notify message in intr pipe.\n" | |||
| 562 | "Please send your dmesg to <bugs@openbsd.org>, thanks.\n", | |||
| 563 | sc->sc_dev.dv_xname); | |||
| 564 | printf("%s: intr buffer 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", | |||
| 565 | sc->sc_dev.dv_xname, | |||
| 566 | sc->sc_intr_buf[0], sc->sc_intr_buf[1], | |||
| 567 | sc->sc_intr_buf[2], sc->sc_intr_buf[3], | |||
| 568 | sc->sc_intr_buf[4], sc->sc_intr_buf[5], | |||
| 569 | sc->sc_intr_buf[6]); | |||
| 570 | #else | |||
| 571 | DPRINTF(("%s: umsm_intr: unknown message type(0x%02x)\n", | |||
| 572 | sc->sc_dev.dv_xname, buf->bmRequestType)); | |||
| 573 | #endif | |||
| 574 | return; | |||
| 575 | } | |||
| 576 | ||||
| 577 | if (buf->bNotification == UCDC_N_SERIAL_STATE0x20) { | |||
| 578 | /* invalid message length, discard it */ | |||
| 579 | if (UGETW(buf->wLength)(*(u_int16_t *)(buf->wLength)) != 2) | |||
| 580 | return; | |||
| 581 | /* XXX: sc_lsr is always 0 */ | |||
| 582 | sc->sc_lsr = sc->sc_msr = 0; | |||
| 583 | mstatus = buf->data[0]; | |||
| 584 | if (ISSET(mstatus, UCDC_N_SERIAL_RI)((mstatus) & (0x08))) | |||
| 585 | sc->sc_msr |= UMSR_RI0x40; | |||
| 586 | if (ISSET(mstatus, UCDC_N_SERIAL_DSR)((mstatus) & (0x02))) | |||
| 587 | sc->sc_msr |= UMSR_DSR0x20; | |||
| 588 | if (ISSET(mstatus, UCDC_N_SERIAL_DCD)((mstatus) & (0x01))) | |||
| 589 | sc->sc_msr |= UMSR_DCD0x80; | |||
| 590 | } else if (buf->bNotification != UCDC_N_CONNECTION_SPEED_CHANGE0x2a) { | |||
| 591 | DPRINTF(("%s: umsm_intr: unknown notify message (0x%02x)\n", | |||
| 592 | sc->sc_dev.dv_xname, buf->bNotification)); | |||
| 593 | return; | |||
| 594 | } | |||
| 595 | ||||
| 596 | ucom_status_change((struct ucom_softc *)sc->sc_subdev); | |||
| 597 | } | |||
| 598 | ||||
| 599 | void | |||
| 600 | umsm_get_status(void *addr, int portno, u_char *lsr, u_char *msr) | |||
| 601 | { | |||
| 602 | struct umsm_softc *sc = addr; | |||
| 603 | ||||
| 604 | if (lsr != NULL((void *)0)) | |||
| 605 | *lsr = sc->sc_lsr; | |||
| 606 | if (msr != NULL((void *)0)) | |||
| 607 | *msr = sc->sc_msr; | |||
| 608 | } | |||
| 609 | ||||
| 610 | void | |||
| 611 | umsm_set(void *addr, int portno, int reg, int onoff) | |||
| 612 | { | |||
| 613 | struct umsm_softc *sc = addr; | |||
| 614 | usb_device_request_t req; | |||
| 615 | int ls; | |||
| 616 | ||||
| 617 | switch (reg) { | |||
| 618 | case UCOM_SET_DTR1: | |||
| 619 | if (sc->sc_dtr == onoff) | |||
| 620 | return; | |||
| 621 | sc->sc_dtr = onoff; | |||
| 622 | break; | |||
| 623 | case UCOM_SET_RTS2: | |||
| 624 | if (sc->sc_rts == onoff) | |||
| 625 | return; | |||
| 626 | sc->sc_rts = onoff; | |||
| 627 | break; | |||
| 628 | default: | |||
| 629 | return; | |||
| 630 | } | |||
| 631 | ||||
| 632 | /* build a usb request */ | |||
| 633 | ls = (sc->sc_dtr ? UCDC_LINE_DTR0x0001 : 0) | | |||
| 634 | (sc->sc_rts ? UCDC_LINE_RTS0x0002 : 0); | |||
| 635 | req.bmRequestType = UT_WRITE_CLASS_INTERFACE(0x00 | 0x20 | 0x01); | |||
| 636 | req.bRequest = UCDC_SET_CONTROL_LINE_STATE0x22; | |||
| 637 | USETW(req.wValue, ls)(*(u_int16_t *)(req.wValue) = (ls)); | |||
| 638 | USETW(req.wIndex, sc->sc_iface_no)(*(u_int16_t *)(req.wIndex) = (sc->sc_iface_no)); | |||
| 639 | USETW(req.wLength, 0)(*(u_int16_t *)(req.wLength) = (0)); | |||
| 640 | ||||
| 641 | (void)usbd_do_request(sc->sc_udev, &req, 0); | |||
| 642 | } | |||
| 643 | ||||
| 644 | usbd_status | |||
| 645 | umsm_huawei_changemode(struct usbd_device *dev) | |||
| 646 | { | |||
| 647 | usb_device_request_t req; | |||
| 648 | usbd_status err; | |||
| 649 | ||||
| 650 | req.bmRequestType = UT_WRITE_DEVICE(0x00 | 0x00 | 0x00); | |||
| 651 | req.bRequest = UR_SET_FEATURE0x03; | |||
| 652 | USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP)(*(u_int16_t *)(req.wValue) = (1)); | |||
| 653 | USETW(req.wIndex, E220_MODE_CHANGE_REQUEST)(*(u_int16_t *)(req.wIndex) = (0x2)); | |||
| 654 | USETW(req.wLength, 0)(*(u_int16_t *)(req.wLength) = (0)); | |||
| 655 | ||||
| 656 | err = usbd_do_request(dev, &req, 0); | |||
| 657 | if (err) | |||
| 658 | return (EIO5); | |||
| 659 | ||||
| 660 | return (0); | |||
| 661 | } | |||
| 662 | ||||
| 663 | usbd_status | |||
| 664 | umsm_truinstall_changemode(struct usbd_device *dev) | |||
| 665 | { | |||
| 666 | usb_device_request_t req; | |||
| 667 | usbd_status err; | |||
| 668 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE(0x00 | 0x40 | 0x00); | |||
| 669 | req.bRequest = TRUINSTALL_CHANGEMODE_REQUEST0x0b; | |||
| 670 | USETW(req.wValue, 0x1)(*(u_int16_t *)(req.wValue) = (0x1)); | |||
| 671 | USETW(req.wIndex, 0)(*(u_int16_t *)(req.wIndex) = (0)); | |||
| 672 | USETW(req.wLength, 0)(*(u_int16_t *)(req.wLength) = (0)); | |||
| 673 | ||||
| 674 | err = usbd_do_request(dev, &req, 0); | |||
| 675 | if (err) | |||
| 676 | return (EIO5); | |||
| 677 | ||||
| 678 | return (0); | |||
| 679 | } | |||
| 680 | ||||
| 681 | usbd_status | |||
| 682 | umsm_umass_changemode(struct umsm_softc *sc) | |||
| 683 | { | |||
| 684 | #define UMASS_CMD_REZERO_UNIT0x01 0x01 | |||
| 685 | #define UMASS_CMD_START_STOP0x1b 0x1b | |||
| 686 | #define UMASS_CMDPARAM_EJECT0x02 0x02 | |||
| 687 | #define UMASS_SERVICE_ACTION_OUT0x9f 0x9f | |||
| 688 | usb_interface_descriptor_t *id; | |||
| 689 | usb_endpoint_descriptor_t *ed; | |||
| 690 | struct usbd_xfer *xfer; | |||
| 691 | struct usbd_pipe *cmdpipe; | |||
| 692 | usbd_status err; | |||
| 693 | u_int32_t n; | |||
| 694 | void *bufp; | |||
| 695 | int target_ep, i; | |||
| 696 | ||||
| 697 | struct umass_bbb_cbw cbw; | |||
| 698 | static int dCBWTag = 0x12345678; | |||
| 699 | ||||
| 700 | USETDW(cbw.dCBWSignature, CBWSIGNATURE)(*(u_int32_t *)(cbw.dCBWSignature) = (0x43425355)); | |||
| 701 | USETDW(cbw.dCBWTag, dCBWTag)(*(u_int32_t *)(cbw.dCBWTag) = (dCBWTag)); | |||
| 702 | cbw.bCBWLUN = 0; | |||
| 703 | cbw.bCDBLength= 6; | |||
| 704 | bzero(cbw.CBWCDB, sizeof(cbw.CBWCDB))__builtin_bzero((cbw.CBWCDB), (sizeof(cbw.CBWCDB))); | |||
| 705 | ||||
| 706 | switch (sc->sc_flag) { | |||
| 707 | case DEV_UMASS10x0010: | |||
| 708 | USETDW(cbw.dCBWDataTransferLength, 0x0)(*(u_int32_t *)(cbw.dCBWDataTransferLength) = (0x0)); | |||
| 709 | cbw.bCBWFlags = CBWFLAGS_OUT0x00; | |||
| 710 | cbw.CBWCDB[0] = UMASS_CMD_REZERO_UNIT0x01; | |||
| 711 | cbw.CBWCDB[1] = 0x0; /* target LUN: 0 */ | |||
| 712 | break; | |||
| 713 | case DEV_UMASS20x0020: | |||
| 714 | USETDW(cbw.dCBWDataTransferLength, 0x1)(*(u_int32_t *)(cbw.dCBWDataTransferLength) = (0x1)); | |||
| 715 | cbw.bCBWFlags = CBWFLAGS_IN0x80; | |||
| 716 | cbw.CBWCDB[0] = UMASS_CMD_REZERO_UNIT0x01; | |||
| 717 | cbw.CBWCDB[1] = 0x0; /* target LUN: 0 */ | |||
| 718 | break; | |||
| 719 | case DEV_UMASS30x0040: /* longcheer */ | |||
| 720 | USETDW(cbw.dCBWDataTransferLength, 0x80)(*(u_int32_t *)(cbw.dCBWDataTransferLength) = (0x80)); | |||
| 721 | cbw.bCBWFlags = CBWFLAGS_IN0x80; | |||
| 722 | cbw.CBWCDB[0] = 0x06; | |||
| 723 | cbw.CBWCDB[1] = 0xf5; | |||
| 724 | cbw.CBWCDB[2] = 0x04; | |||
| 725 | cbw.CBWCDB[3] = 0x02; | |||
| 726 | cbw.CBWCDB[4] = 0x52; | |||
| 727 | cbw.CBWCDB[5] = 0x70; | |||
| 728 | break; | |||
| 729 | case DEV_UMASS40x0080: | |||
| 730 | USETDW(cbw.dCBWDataTransferLength, 0x0)(*(u_int32_t *)(cbw.dCBWDataTransferLength) = (0x0)); | |||
| 731 | cbw.bCBWFlags = CBWFLAGS_OUT0x00; | |||
| 732 | cbw.CBWCDB[0] = UMASS_CMD_START_STOP0x1b; | |||
| 733 | cbw.CBWCDB[1] = 0x00; /* target LUN: 0 */ | |||
| 734 | cbw.CBWCDB[4] = UMASS_CMDPARAM_EJECT0x02; | |||
| 735 | break; | |||
| 736 | case DEV_UMASS50x0100: | |||
| 737 | cbw.bCBWFlags = CBWFLAGS_OUT0x00; | |||
| 738 | cbw.CBWCDB[0] = 0x11; | |||
| 739 | cbw.CBWCDB[1] = 0x06; | |||
| 740 | break; | |||
| 741 | case DEV_UMASS60x0200: /* ZTE */ | |||
| 742 | USETDW(cbw.dCBWDataTransferLength, 0x20)(*(u_int32_t *)(cbw.dCBWDataTransferLength) = (0x20)); | |||
| 743 | cbw.bCBWFlags = CBWFLAGS_IN0x80; | |||
| 744 | cbw.bCDBLength= 12; | |||
| 745 | cbw.CBWCDB[0] = 0x85; | |||
| 746 | cbw.CBWCDB[1] = 0x01; | |||
| 747 | cbw.CBWCDB[2] = 0x01; | |||
| 748 | cbw.CBWCDB[3] = 0x01; | |||
| 749 | cbw.CBWCDB[4] = 0x18; | |||
| 750 | cbw.CBWCDB[5] = 0x01; | |||
| 751 | cbw.CBWCDB[6] = 0x01; | |||
| 752 | cbw.CBWCDB[7] = 0x01; | |||
| 753 | cbw.CBWCDB[8] = 0x01; | |||
| 754 | cbw.CBWCDB[9] = 0x01; | |||
| 755 | break; | |||
| 756 | case DEV_UMASS70x0400: /* ZTE */ | |||
| 757 | USETDW(cbw.dCBWDataTransferLength, 0xc0)(*(u_int32_t *)(cbw.dCBWDataTransferLength) = (0xc0)); | |||
| 758 | cbw.bCBWFlags = CBWFLAGS_IN0x80; | |||
| 759 | cbw.CBWCDB[0] = UMASS_SERVICE_ACTION_OUT0x9f; | |||
| 760 | cbw.CBWCDB[1] = 0x03; | |||
| 761 | break; | |||
| 762 | case DEV_UMASS80x1000: | |||
| 763 | USETDW(cbw.dCBWDataTransferLength, 0x0)(*(u_int32_t *)(cbw.dCBWDataTransferLength) = (0x0)); | |||
| 764 | cbw.bCBWFlags = CBWFLAGS_OUT0x00; | |||
| 765 | cbw.CBWCDB[0] = 0xf0; | |||
| 766 | cbw.CBWCDB[1] = 0x01; | |||
| 767 | cbw.CBWCDB[2] = 0x03; | |||
| 768 | break; | |||
| 769 | default: | |||
| 770 | DPRINTF(("%s: unknown device type.\n", sc->sc_dev.dv_xname)); | |||
| 771 | break; | |||
| 772 | } | |||
| 773 | ||||
| 774 | /* get command endpoint address */ | |||
| 775 | id = usbd_get_interface_descriptor(sc->sc_iface); | |||
| 776 | for (i = 0; i < id->bNumEndpoints; i++) { | |||
| 777 | ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); | |||
| 778 | if (ed == NULL((void *)0)) { | |||
| 779 | return (USBD_IOERROR); | |||
| 780 | } | |||
| 781 | ||||
| 782 | if (UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_OUT0x00 && | |||
| 783 | UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_BULK0x02) | |||
| 784 | target_ep = ed->bEndpointAddress; | |||
| 785 | } | |||
| 786 | ||||
| 787 | /* open command endpoint */ | |||
| 788 | err = usbd_open_pipe(sc->sc_iface, target_ep, | |||
| ||||
| 789 | USBD_EXCLUSIVE_USE0x01, &cmdpipe); | |||
| 790 | if (err) { | |||
| 791 | DPRINTF(("%s: open pipe for modem change cmd failed: %s\n", | |||
| 792 | sc->sc_dev.dv_xname, usbd_errstr(err))); | |||
| 793 | return (err); | |||
| 794 | } | |||
| 795 | ||||
| 796 | xfer = usbd_alloc_xfer(sc->sc_udev); | |||
| 797 | if (xfer == NULL((void *)0)) { | |||
| 798 | usbd_close_pipe(cmdpipe); | |||
| 799 | return (USBD_NOMEM); | |||
| 800 | } else { | |||
| 801 | bufp = usbd_alloc_buffer(xfer, UMASS_BBB_CBW_SIZE31); | |||
| 802 | if (bufp == NULL((void *)0)) | |||
| 803 | err = USBD_NOMEM; | |||
| 804 | else { | |||
| 805 | n = UMASS_BBB_CBW_SIZE31; | |||
| 806 | memcpy(bufp, &cbw, UMASS_BBB_CBW_SIZE)__builtin_memcpy((bufp), (&cbw), (31)); | |||
| 807 | usbd_setup_xfer(xfer, cmdpipe, 0, bufp, n, | |||
| 808 | USBD_NO_COPY0x01 | USBD_SYNCHRONOUS0x02, 0, NULL((void *)0)); | |||
| 809 | err = usbd_transfer(xfer); | |||
| 810 | if (err) { | |||
| 811 | usbd_clear_endpoint_stall(cmdpipe); | |||
| 812 | DPRINTF(("%s: send error:%s", __func__, | |||
| 813 | usbd_errstr(err))); | |||
| 814 | } | |||
| 815 | } | |||
| 816 | usbd_close_pipe(cmdpipe); | |||
| 817 | usbd_free_buffer(xfer); | |||
| 818 | usbd_free_xfer(xfer); | |||
| 819 | } | |||
| 820 | ||||
| 821 | return (err); | |||
| 822 | } |