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