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