xref: /freebsd/sys/dev/usb/net/if_usie.c (revision 10b59a9b4add0320d52c15ce057dd697261e7dfc)
1 /*-
2  * Copyright (c) 2011 Anybots Inc
3  * written by Akinori Furukoshi <moonlightakkiy@yahoo.ca>
4  *  - ucom part is based on u3g.c
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/queue.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/bus.h>
37 #include <sys/module.h>
38 #include <sys/sockio.h>
39 #include <sys/socket.h>
40 #include <sys/lock.h>
41 #include <sys/mutex.h>
42 #include <sys/condvar.h>
43 #include <sys/sysctl.h>
44 #include <sys/malloc.h>
45 #include <sys/taskqueue.h>
46 
47 #include <machine/bus.h>
48 
49 #include <net/if.h>
50 #include <net/if_types.h>
51 #include <net/netisr.h>
52 #include <net/bpf.h>
53 #include <net/ethernet.h>
54 
55 #include <netinet/in.h>
56 #include <netinet/ip.h>
57 #include <netinet/ip6.h>
58 #include <netinet/udp.h>
59 
60 #include <net80211/ieee80211_ioctl.h>
61 
62 #include <dev/usb/usb.h>
63 #include <dev/usb/usbdi.h>
64 #include <dev/usb/usbdi_util.h>
65 #include <dev/usb/usb_cdc.h>
66 #include "usbdevs.h"
67 
68 #define	USB_DEBUG_VAR usie_debug
69 #include <dev/usb/usb_debug.h>
70 #include <dev/usb/usb_process.h>
71 #include <dev/usb/usb_msctest.h>
72 
73 #include <dev/usb/serial/usb_serial.h>
74 
75 #include <dev/usb/net/if_usievar.h>
76 
77 #ifdef	USB_DEBUG
78 static int usie_debug = 0;
79 
80 static SYSCTL_NODE(_hw_usb, OID_AUTO, usie, CTLFLAG_RW, 0, "sierra USB modem");
81 SYSCTL_INT(_hw_usb_usie, OID_AUTO, debug, CTLFLAG_RW, &usie_debug, 0,
82     "usie debug level");
83 #endif
84 
85 /* Sierra Wireless Direct IP modems */
86 static const STRUCT_USB_HOST_ID usie_devs[] = {
87 #define	USIE_DEV(v, d) {				\
88     USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##d) }
89 	USIE_DEV(SIERRA, MC8700),
90 	USIE_DEV(SIERRA, TRUINSTALL),
91 	USIE_DEV(AIRPRIME, USB308),
92 #undef	USIE_DEV
93 };
94 
95 static device_probe_t usie_probe;
96 static device_attach_t usie_attach;
97 static device_detach_t usie_detach;
98 
99 static void usie_uc_update_line_state(struct ucom_softc *, uint8_t);
100 static void usie_uc_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *);
101 static void usie_uc_cfg_set_dtr(struct ucom_softc *, uint8_t);
102 static void usie_uc_cfg_set_rts(struct ucom_softc *, uint8_t);
103 static void usie_uc_cfg_open(struct ucom_softc *);
104 static void usie_uc_cfg_close(struct ucom_softc *);
105 static void usie_uc_start_read(struct ucom_softc *);
106 static void usie_uc_stop_read(struct ucom_softc *);
107 static void usie_uc_start_write(struct ucom_softc *);
108 static void usie_uc_stop_write(struct ucom_softc *);
109 
110 static usb_callback_t usie_uc_tx_callback;
111 static usb_callback_t usie_uc_rx_callback;
112 static usb_callback_t usie_uc_status_callback;
113 static usb_callback_t usie_if_tx_callback;
114 static usb_callback_t usie_if_rx_callback;
115 static usb_callback_t usie_if_status_callback;
116 
117 static void usie_if_sync_to(void *);
118 static void usie_if_sync_cb(void *, int);
119 static void usie_if_status_cb(void *, int);
120 
121 static void usie_if_start(struct ifnet *);
122 static int usie_if_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct route *);
123 static void usie_if_init(void *);
124 static void usie_if_stop(struct usie_softc *);
125 static int usie_if_ioctl(struct ifnet *, u_long, caddr_t);
126 
127 static int usie_do_request(struct usie_softc *, struct usb_device_request *, void *);
128 static int usie_if_cmd(struct usie_softc *, uint8_t);
129 static void usie_cns_req(struct usie_softc *, uint32_t, uint16_t);
130 static void usie_cns_rsp(struct usie_softc *, struct usie_cns *);
131 static void usie_hip_rsp(struct usie_softc *, uint8_t *, uint32_t);
132 static int usie_driver_loaded(struct module *, int, void *);
133 
134 static const struct usb_config usie_uc_config[USIE_UC_N_XFER] = {
135 	[USIE_UC_STATUS] = {
136 		.type = UE_INTERRUPT,
137 		.endpoint = UE_ADDR_ANY,
138 		.direction = UE_DIR_IN,
139 		.bufsize = 0,		/* use wMaxPacketSize */
140 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
141 		.callback = &usie_uc_status_callback,
142 	},
143 	[USIE_UC_RX] = {
144 		.type = UE_BULK,
145 		.endpoint = UE_ADDR_ANY,
146 		.direction = UE_DIR_IN,
147 		.bufsize = USIE_BUFSIZE,
148 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1,},
149 		.callback = &usie_uc_rx_callback,
150 	},
151 	[USIE_UC_TX] = {
152 		.type = UE_BULK,
153 		.endpoint = UE_ADDR_ANY,
154 		.direction = UE_DIR_OUT,
155 		.bufsize = USIE_BUFSIZE,
156 		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
157 		.callback = &usie_uc_tx_callback,
158 	}
159 };
160 
161 static const struct usb_config usie_if_config[USIE_IF_N_XFER] = {
162 	[USIE_IF_STATUS] = {
163 		.type = UE_INTERRUPT,
164 		.endpoint = UE_ADDR_ANY,
165 		.direction = UE_DIR_IN,
166 		.bufsize = 0,		/* use wMaxPacketSize */
167 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
168 		.callback = &usie_if_status_callback,
169 	},
170 	[USIE_IF_RX] = {
171 		.type = UE_BULK,
172 		.endpoint = UE_ADDR_ANY,
173 		.direction = UE_DIR_IN,
174 		.bufsize = USIE_BUFSIZE,
175 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
176 		.callback = &usie_if_rx_callback,
177 	},
178 	[USIE_IF_TX] = {
179 		.type = UE_BULK,
180 		.endpoint = UE_ADDR_ANY,
181 		.direction = UE_DIR_OUT,
182 		.bufsize = MAX(USIE_BUFSIZE, MCLBYTES),
183 		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
184 		.callback = &usie_if_tx_callback,
185 	}
186 };
187 
188 static device_method_t usie_methods[] = {
189 	DEVMETHOD(device_probe, usie_probe),
190 	DEVMETHOD(device_attach, usie_attach),
191 	DEVMETHOD(device_detach, usie_detach),
192 	{0, 0}
193 };
194 
195 static driver_t usie_driver = {
196 	.name = "usie",
197 	.methods = usie_methods,
198 	.size = sizeof(struct usie_softc),
199 };
200 
201 static devclass_t usie_devclass;
202 static eventhandler_tag usie_etag;
203 
204 DRIVER_MODULE(usie, uhub, usie_driver, usie_devclass, usie_driver_loaded, 0);
205 MODULE_DEPEND(usie, ucom, 1, 1, 1);
206 MODULE_DEPEND(usie, usb, 1, 1, 1);
207 MODULE_VERSION(usie, 1);
208 
209 static const struct ucom_callback usie_uc_callback = {
210 	.ucom_cfg_get_status = &usie_uc_cfg_get_status,
211 	.ucom_cfg_set_dtr = &usie_uc_cfg_set_dtr,
212 	.ucom_cfg_set_rts = &usie_uc_cfg_set_rts,
213 	.ucom_cfg_open = &usie_uc_cfg_open,
214 	.ucom_cfg_close = &usie_uc_cfg_close,
215 	.ucom_start_read = &usie_uc_start_read,
216 	.ucom_stop_read = &usie_uc_stop_read,
217 	.ucom_start_write = &usie_uc_start_write,
218 	.ucom_stop_write = &usie_uc_stop_write,
219 };
220 
221 static void
222 usie_autoinst(void *arg, struct usb_device *udev,
223     struct usb_attach_arg *uaa)
224 {
225 	struct usb_interface *iface;
226 	struct usb_interface_descriptor *id;
227 	struct usb_device_request req;
228 	int err;
229 
230 	if (uaa->dev_state != UAA_DEV_READY)
231 		return;
232 
233 	iface = usbd_get_iface(udev, 0);
234 	if (iface == NULL)
235 		return;
236 
237 	id = iface->idesc;
238 	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
239 		return;
240 
241 	if (usbd_lookup_id_by_uaa(usie_devs, sizeof(usie_devs), uaa) != 0)
242 		return;			/* no device match */
243 
244 	if (bootverbose) {
245 		DPRINTF("Ejecting %s %s\n",
246 		    usb_get_manufacturer(udev),
247 		    usb_get_product(udev));
248 	}
249 	req.bmRequestType = UT_VENDOR;
250 	req.bRequest = UR_SET_INTERFACE;
251 	USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
252 	USETW(req.wIndex, UHF_PORT_CONNECTION);
253 	USETW(req.wLength, 0);
254 
255 	/* at this moment there is no mutex */
256 	err = usbd_do_request_flags(udev, NULL, &req,
257 	    NULL, 0, NULL, 250 /* ms */ );
258 
259 	/* success, mark the udev as disappearing */
260 	if (err == 0)
261 		uaa->dev_state = UAA_DEV_EJECTING;
262 }
263 
264 static int
265 usie_probe(device_t self)
266 {
267 	struct usb_attach_arg *uaa = device_get_ivars(self);
268 
269 	if (uaa->usb_mode != USB_MODE_HOST)
270 		return (ENXIO);
271 	if (uaa->info.bConfigIndex != USIE_CNFG_INDEX)
272 		return (ENXIO);
273 	if (uaa->info.bIfaceIndex != USIE_IFACE_INDEX)
274 		return (ENXIO);
275 	if (uaa->info.bInterfaceClass != UICLASS_VENDOR)
276 		return (ENXIO);
277 
278 	return (usbd_lookup_id_by_uaa(usie_devs, sizeof(usie_devs), uaa));
279 }
280 
281 static int
282 usie_attach(device_t self)
283 {
284 	struct usie_softc *sc = device_get_softc(self);
285 	struct usb_attach_arg *uaa = device_get_ivars(self);
286 	struct ifnet *ifp;
287 	struct usb_interface *iface;
288 	struct usb_interface_descriptor *id;
289 	struct usb_device_request req;
290 	int err;
291 	uint16_t fwattr;
292 	uint8_t iface_index;
293 	uint8_t ifidx;
294 	uint8_t start;
295 
296 	device_set_usb_desc(self);
297 	sc->sc_udev = uaa->device;
298 	sc->sc_dev = self;
299 
300 	mtx_init(&sc->sc_mtx, "usie", MTX_NETWORK_LOCK, MTX_DEF);
301 
302 	TASK_INIT(&sc->sc_if_status_task, 0, usie_if_status_cb, sc);
303 	TASK_INIT(&sc->sc_if_sync_task, 0, usie_if_sync_cb, sc);
304 
305 	usb_callout_init_mtx(&sc->sc_if_sync_ch, &sc->sc_mtx, 0);
306 
307 	mtx_lock(&sc->sc_mtx);
308 
309 	/* set power mode to D0 */
310 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
311 	req.bRequest = USIE_POWER;
312 	USETW(req.wValue, 0);
313 	USETW(req.wIndex, 0);
314 	USETW(req.wLength, 0);
315 	if (usie_do_request(sc, &req, NULL)) {
316 		mtx_unlock(&sc->sc_mtx);
317 		goto detach;
318 	}
319 	/* read fw attr */
320 	fwattr = 0;
321 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
322 	req.bRequest = USIE_FW_ATTR;
323 	USETW(req.wValue, 0);
324 	USETW(req.wIndex, 0);
325 	USETW(req.wLength, sizeof(fwattr));
326 	if (usie_do_request(sc, &req, &fwattr)) {
327 		mtx_unlock(&sc->sc_mtx);
328 		goto detach;
329 	}
330 	mtx_unlock(&sc->sc_mtx);
331 
332 	/* check DHCP supports */
333 	DPRINTF("fwattr=%x\n", fwattr);
334 	if (!(fwattr & USIE_FW_DHCP)) {
335 		device_printf(self, "DHCP is not supported. A firmware upgrade might be needed.\n");
336 	}
337 
338 	/* find available interfaces */
339 	sc->sc_nucom = 0;
340 	for (ifidx = 0; ifidx < USIE_IFACE_MAX; ifidx++) {
341 		iface = usbd_get_iface(uaa->device, ifidx);
342 		if (iface == NULL)
343 			break;
344 
345 		id = usbd_get_interface_descriptor(iface);
346 		if ((id == NULL) || (id->bInterfaceClass != UICLASS_VENDOR))
347 			continue;
348 
349 		/* setup Direct IP transfer */
350 		if (id->bInterfaceNumber >= 7 && id->bNumEndpoints == 3) {
351 			sc->sc_if_ifnum = id->bInterfaceNumber;
352 			iface_index = ifidx;
353 
354 			DPRINTF("ifnum=%d, ifidx=%d\n",
355 			    sc->sc_if_ifnum, ifidx);
356 
357 			err = usbd_transfer_setup(uaa->device,
358 			    &iface_index, sc->sc_if_xfer, usie_if_config,
359 			    USIE_IF_N_XFER, sc, &sc->sc_mtx);
360 
361 			if (err == 0)
362 				continue;
363 
364 			device_printf(self,
365 			    "could not allocate USB transfers on "
366 			    "iface_index=%d, err=%s\n",
367 			    iface_index, usbd_errstr(err));
368 			goto detach;
369 		}
370 
371 		/* setup ucom */
372 		if (sc->sc_nucom >= USIE_UCOM_MAX)
373 			continue;
374 
375 		usbd_set_parent_iface(uaa->device, ifidx,
376 		    uaa->info.bIfaceIndex);
377 
378 		DPRINTF("NumEndpoints=%d bInterfaceNumber=%d\n",
379 		    id->bNumEndpoints, id->bInterfaceNumber);
380 
381 		if (id->bNumEndpoints == 2) {
382 			sc->sc_uc_xfer[sc->sc_nucom][0] = NULL;
383 			start = 1;
384 		} else
385 			start = 0;
386 
387 		err = usbd_transfer_setup(uaa->device, &ifidx,
388 		    sc->sc_uc_xfer[sc->sc_nucom] + start,
389 		    usie_uc_config + start, USIE_UC_N_XFER - start,
390 		    &sc->sc_ucom[sc->sc_nucom], &sc->sc_mtx);
391 
392 		if (err != 0) {
393 			DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(err));
394 			continue;
395 		}
396 
397 		mtx_lock(&sc->sc_mtx);
398 		for (; start < USIE_UC_N_XFER; start++)
399 			usbd_xfer_set_stall(sc->sc_uc_xfer[sc->sc_nucom][start]);
400 		mtx_unlock(&sc->sc_mtx);
401 
402 		sc->sc_uc_ifnum[sc->sc_nucom] = id->bInterfaceNumber;
403 
404 		sc->sc_nucom++;		/* found a port */
405 	}
406 
407 	if (sc->sc_nucom == 0) {
408 		device_printf(self, "no comports found\n");
409 		goto detach;
410 	}
411 
412 	err = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom,
413 	    sc->sc_nucom, sc, &usie_uc_callback, &sc->sc_mtx);
414 
415 	if (err != 0) {
416 		DPRINTF("ucom_attach failed\n");
417 		goto detach;
418 	}
419 	DPRINTF("Found %d interfaces.\n", sc->sc_nucom);
420 
421 	/* setup ifnet (Direct IP) */
422 	sc->sc_ifp = ifp = if_alloc(IFT_OTHER);
423 
424 	if (ifp == NULL) {
425 		device_printf(self, "Could not allocate a network interface\n");
426 		goto detach;
427 	}
428 	if_initname(ifp, "usie", device_get_unit(self));
429 
430 	ifp->if_softc = sc;
431 	ifp->if_mtu = USIE_MTU_MAX;
432 	ifp->if_flags |= IFF_NOARP;
433 	ifp->if_init = usie_if_init;
434 	ifp->if_ioctl = usie_if_ioctl;
435 	ifp->if_start = usie_if_start;
436 	ifp->if_output = usie_if_output;
437 	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
438 	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
439 	IFQ_SET_READY(&ifp->if_snd);
440 
441 	if_attach(ifp);
442 	bpfattach(ifp, DLT_RAW, 0);
443 
444 	if (fwattr & USIE_PM_AUTO) {
445 		usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE);
446 		DPRINTF("enabling automatic suspend and resume\n");
447 	} else {
448 		usbd_set_power_mode(uaa->device, USB_POWER_MODE_ON);
449 		DPRINTF("USB power is always ON\n");
450 	}
451 
452 	DPRINTF("device attached\n");
453 	return (0);
454 
455 detach:
456 	usie_detach(self);
457 	return (ENOMEM);
458 }
459 
460 static int
461 usie_detach(device_t self)
462 {
463 	struct usie_softc *sc = device_get_softc(self);
464 	uint8_t x;
465 
466 	/* detach ifnet */
467 	if (sc->sc_ifp != NULL) {
468 		usie_if_stop(sc);
469 		usbd_transfer_unsetup(sc->sc_if_xfer, USIE_IF_N_XFER);
470 		bpfdetach(sc->sc_ifp);
471 		if_detach(sc->sc_ifp);
472 		if_free(sc->sc_ifp);
473 		sc->sc_ifp = NULL;
474 	}
475 	/* detach ucom */
476 	if (sc->sc_nucom > 0)
477 		ucom_detach(&sc->sc_super_ucom, sc->sc_ucom);
478 
479 	/* stop all USB transfers */
480 	usbd_transfer_unsetup(sc->sc_if_xfer, USIE_IF_N_XFER);
481 
482 	for (x = 0; x != USIE_UCOM_MAX; x++)
483 		usbd_transfer_unsetup(sc->sc_uc_xfer[x], USIE_UC_N_XFER);
484 
485 	mtx_destroy(&sc->sc_mtx);
486 
487 	return (0);
488 }
489 
490 static void
491 usie_uc_update_line_state(struct ucom_softc *ucom, uint8_t ls)
492 {
493 	struct usie_softc *sc = ucom->sc_parent;
494 	struct usb_device_request req;
495 
496 	if (sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_STATUS] == NULL)
497 		return;
498 
499 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
500 	req.bRequest = USIE_LINK_STATE;
501 	USETW(req.wValue, ls);
502 	USETW(req.wIndex, sc->sc_uc_ifnum[ucom->sc_subunit]);
503 	USETW(req.wLength, 0);
504 
505 	DPRINTF("sc_uc_ifnum=%d\n", sc->sc_uc_ifnum[ucom->sc_subunit]);
506 
507 	usie_do_request(sc, &req, NULL);
508 }
509 
510 static void
511 usie_uc_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
512 {
513 	struct usie_softc *sc = ucom->sc_parent;
514 
515 	*msr = sc->sc_msr;
516 	*lsr = sc->sc_lsr;
517 }
518 
519 static void
520 usie_uc_cfg_set_dtr(struct ucom_softc *ucom, uint8_t flag)
521 {
522 	uint8_t dtr;
523 
524 	dtr = flag ? USIE_LS_DTR : 0;
525 	usie_uc_update_line_state(ucom, dtr);
526 }
527 
528 static void
529 usie_uc_cfg_set_rts(struct ucom_softc *ucom, uint8_t flag)
530 {
531 	uint8_t rts;
532 
533 	rts = flag ? USIE_LS_RTS : 0;
534 	usie_uc_update_line_state(ucom, rts);
535 }
536 
537 static void
538 usie_uc_cfg_open(struct ucom_softc *ucom)
539 {
540 	struct usie_softc *sc = ucom->sc_parent;
541 
542 	/* usbd_transfer_start() is NULL safe */
543 
544 	usbd_transfer_start(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_STATUS]);
545 }
546 
547 static void
548 usie_uc_cfg_close(struct ucom_softc *ucom)
549 {
550 	struct usie_softc *sc = ucom->sc_parent;
551 
552 	usbd_transfer_stop(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_STATUS]);
553 }
554 
555 static void
556 usie_uc_start_read(struct ucom_softc *ucom)
557 {
558 	struct usie_softc *sc = ucom->sc_parent;
559 
560 	usbd_transfer_start(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_RX]);
561 }
562 
563 static void
564 usie_uc_stop_read(struct ucom_softc *ucom)
565 {
566 	struct usie_softc *sc = ucom->sc_parent;
567 
568 	usbd_transfer_stop(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_RX]);
569 }
570 
571 static void
572 usie_uc_start_write(struct ucom_softc *ucom)
573 {
574 	struct usie_softc *sc = ucom->sc_parent;
575 
576 	usbd_transfer_start(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_TX]);
577 }
578 
579 static void
580 usie_uc_stop_write(struct ucom_softc *ucom)
581 {
582 	struct usie_softc *sc = ucom->sc_parent;
583 
584 	usbd_transfer_stop(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_TX]);
585 }
586 
587 static void
588 usie_uc_rx_callback(struct usb_xfer *xfer, usb_error_t error)
589 {
590 	struct ucom_softc *ucom = usbd_xfer_softc(xfer);
591 	struct usie_softc *sc = ucom->sc_parent;
592 	struct usb_page_cache *pc;
593 	uint32_t actlen;
594 
595 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
596 
597 	switch (USB_GET_STATE(xfer)) {
598 	case USB_ST_TRANSFERRED:
599 		pc = usbd_xfer_get_frame(xfer, 0);
600 
601 		/* handle CnS response */
602 		if (ucom == sc->sc_ucom && actlen >= USIE_HIPCNS_MIN) {
603 
604 			DPRINTF("transferred=%u\n", actlen);
605 
606 			/* check if it is really CnS reply */
607 			usbd_copy_out(pc, 0, sc->sc_resp_temp, 1);
608 
609 			if (sc->sc_resp_temp[0] == USIE_HIP_FRM_CHR) {
610 
611 				/* verify actlen */
612 				if (actlen > USIE_BUFSIZE)
613 					actlen = USIE_BUFSIZE;
614 
615 				/* get complete message */
616 				usbd_copy_out(pc, 0, sc->sc_resp_temp, actlen);
617 				usie_hip_rsp(sc, sc->sc_resp_temp, actlen);
618 
619 				/* need to fall though */
620 				goto tr_setup;
621 			}
622 			/* else call ucom_put_data() */
623 		}
624 		/* standard ucom transfer */
625 		ucom_put_data(ucom, pc, 0, actlen);
626 
627 		/* fall though */
628 	case USB_ST_SETUP:
629 tr_setup:
630 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
631 		usbd_transfer_submit(xfer);
632 		break;
633 
634 	default:			/* Error */
635 		if (error != USB_ERR_CANCELLED) {
636 			usbd_xfer_set_stall(xfer);
637 			goto tr_setup;
638 		}
639 		break;
640 	}
641 }
642 
643 static void
644 usie_uc_tx_callback(struct usb_xfer *xfer, usb_error_t error)
645 {
646 	struct ucom_softc *ucom = usbd_xfer_softc(xfer);
647 	struct usb_page_cache *pc;
648 	uint32_t actlen;
649 
650 	switch (USB_GET_STATE(xfer)) {
651 	case USB_ST_TRANSFERRED:
652 	case USB_ST_SETUP:
653 tr_setup:
654 		pc = usbd_xfer_get_frame(xfer, 0);
655 
656 		/* handle CnS request */
657 		struct mbuf *m = usbd_xfer_get_priv(xfer);
658 
659 		if (m != NULL) {
660 			usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
661 			usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
662 			usbd_xfer_set_priv(xfer, NULL);
663 			usbd_transfer_submit(xfer);
664 			m_freem(m);
665 			break;
666 		}
667 		/* standard ucom transfer */
668 		if (ucom_get_data(ucom, pc, 0, USIE_BUFSIZE, &actlen)) {
669 			usbd_xfer_set_frame_len(xfer, 0, actlen);
670 			usbd_transfer_submit(xfer);
671 		}
672 		break;
673 
674 	default:			/* Error */
675 		if (error != USB_ERR_CANCELLED) {
676 			usbd_xfer_set_stall(xfer);
677 			goto tr_setup;
678 		}
679 		break;
680 	}
681 }
682 
683 static void
684 usie_uc_status_callback(struct usb_xfer *xfer, usb_error_t error)
685 {
686 	struct usb_page_cache *pc;
687 	struct {
688 		struct usb_device_request req;
689 		uint16_t param;
690 	}      st;
691 	uint32_t actlen;
692 	uint16_t param;
693 
694 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
695 
696 	switch (USB_GET_STATE(xfer)) {
697 	case USB_ST_TRANSFERRED:
698 		DPRINTFN(4, "info received, actlen=%u\n", actlen);
699 
700 		if (actlen < sizeof(st)) {
701 			DPRINTF("data too short actlen=%u\n", actlen);
702 			goto tr_setup;
703 		}
704 		pc = usbd_xfer_get_frame(xfer, 0);
705 		usbd_copy_out(pc, 0, &st, sizeof(st));
706 
707 		if (st.req.bmRequestType == 0xa1 && st.req.bRequest == 0x20) {
708 			struct ucom_softc *ucom = usbd_xfer_softc(xfer);
709 			struct usie_softc *sc = ucom->sc_parent;
710 
711 			param = le16toh(st.param);
712 			DPRINTF("param=%x\n", param);
713 			sc->sc_msr = sc->sc_lsr = 0;
714 			sc->sc_msr |= (param & USIE_DCD) ? SER_DCD : 0;
715 			sc->sc_msr |= (param & USIE_DSR) ? SER_DSR : 0;
716 			sc->sc_msr |= (param & USIE_RI) ? SER_RI : 0;
717 			sc->sc_msr |= (param & USIE_CTS) ? 0 : SER_CTS;
718 			sc->sc_msr |= (param & USIE_RTS) ? SER_RTS : 0;
719 			sc->sc_msr |= (param & USIE_DTR) ? SER_DTR : 0;
720 		}
721 		/* fall though */
722 	case USB_ST_SETUP:
723 tr_setup:
724 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
725 		usbd_transfer_submit(xfer);
726 		break;
727 
728 	default:			/* Error */
729 		DPRINTF("USB transfer error, %s\n",
730 		    usbd_errstr(error));
731 
732 		if (error != USB_ERR_CANCELLED) {
733 			usbd_xfer_set_stall(xfer);
734 			goto tr_setup;
735 		}
736 		break;
737 	}
738 }
739 
740 static void
741 usie_if_rx_callback(struct usb_xfer *xfer, usb_error_t error)
742 {
743 	struct usie_softc *sc = usbd_xfer_softc(xfer);
744 	struct ifnet *ifp = sc->sc_ifp;
745 	struct mbuf *m0;
746 	struct mbuf *m = NULL;
747 	struct usie_desc *rxd;
748 	uint32_t actlen;
749 	uint16_t err;
750 	uint16_t pkt;
751 	uint16_t ipl;
752 	uint16_t len;
753 	uint16_t diff;
754 	uint8_t pad;
755 	uint8_t ipv;
756 
757 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
758 
759 	switch (USB_GET_STATE(xfer)) {
760 	case USB_ST_TRANSFERRED:
761 		DPRINTFN(15, "rx done, actlen=%u\n", actlen);
762 
763 		if (actlen < sizeof(struct usie_hip)) {
764 			DPRINTF("data too short %u\n", actlen);
765 			goto tr_setup;
766 		}
767 		m = sc->sc_rxm;
768 		sc->sc_rxm = NULL;
769 
770 		/* fall though */
771 	case USB_ST_SETUP:
772 tr_setup:
773 
774 		if (sc->sc_rxm == NULL) {
775 			sc->sc_rxm = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR,
776 			    MJUMPAGESIZE /* could be bigger than MCLBYTES */ );
777 		}
778 		if (sc->sc_rxm == NULL) {
779 			DPRINTF("could not allocate Rx mbuf\n");
780 			ifp->if_ierrors++;
781 			usbd_xfer_set_stall(xfer);
782 			usbd_xfer_set_frames(xfer, 0);
783 		} else {
784 			/*
785 			 * Directly loading a mbuf cluster into DMA to
786 			 * save some data copying. This works because
787 			 * there is only one cluster.
788 			 */
789 			usbd_xfer_set_frame_data(xfer, 0,
790 			    mtod(sc->sc_rxm, caddr_t), MIN(MJUMPAGESIZE, USIE_RXSZ_MAX));
791 			usbd_xfer_set_frames(xfer, 1);
792 		}
793 		usbd_transfer_submit(xfer);
794 		break;
795 
796 	default:			/* Error */
797 		DPRINTF("USB transfer error, %s\n", usbd_errstr(error));
798 
799 		if (error != USB_ERR_CANCELLED) {
800 			/* try to clear stall first */
801 			usbd_xfer_set_stall(xfer);
802 			ifp->if_ierrors++;
803 			goto tr_setup;
804 		}
805 		if (sc->sc_rxm != NULL) {
806 			m_freem(sc->sc_rxm);
807 			sc->sc_rxm = NULL;
808 		}
809 		break;
810 	}
811 
812 	if (m == NULL)
813 		return;
814 
815 	mtx_unlock(&sc->sc_mtx);
816 
817 	m->m_pkthdr.len = m->m_len = actlen;
818 
819 	err = pkt = 0;
820 
821 	/* HW can aggregate multiple frames in a single USB xfer */
822 	for (;;) {
823 		rxd = mtod(m, struct usie_desc *);
824 
825 		len = be16toh(rxd->hip.len) & USIE_HIP_IP_LEN_MASK;
826 		pad = (rxd->hip.id & USIE_HIP_PAD) ? 1 : 0;
827 		ipl = (len - pad - ETHER_HDR_LEN);
828 		if (ipl >= len) {
829 			DPRINTF("Corrupt frame\n");
830 			m_freem(m);
831 			break;
832 		}
833 		diff = sizeof(struct usie_desc) + ipl + pad;
834 
835 		if (((rxd->hip.id & USIE_HIP_MASK) != USIE_HIP_IP) ||
836 		    (be16toh(rxd->desc_type) & USIE_TYPE_MASK) != USIE_IP_RX) {
837 			DPRINTF("received wrong type of packet\n");
838 			m->m_data += diff;
839 			m->m_pkthdr.len = (m->m_len -= diff);
840 			err++;
841 			if (m->m_pkthdr.len > 0)
842 				continue;
843 			m_freem(m);
844 			break;
845 		}
846 		switch (be16toh(rxd->ethhdr.ether_type)) {
847 		case ETHERTYPE_IP:
848 			ipv = NETISR_IP;
849 			break;
850 #ifdef INET6
851 		case ETHERTYPE_IPV6:
852 			ipv = NETISR_IPV6;
853 			break;
854 #endif
855 		default:
856 			DPRINTF("unsupported ether type\n");
857 			err++;
858 			break;
859 		}
860 
861 		/* the last packet */
862 		if (m->m_pkthdr.len <= diff) {
863 			m->m_data += (sizeof(struct usie_desc) + pad);
864 			m->m_pkthdr.len = m->m_len = ipl;
865 			m->m_pkthdr.rcvif = ifp;
866 			BPF_MTAP(sc->sc_ifp, m);
867 			netisr_dispatch(ipv, m);
868 			break;
869 		}
870 		/* copy aggregated frames to another mbuf */
871 		m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
872 		if (__predict_false(m0 == NULL)) {
873 			DPRINTF("could not allocate mbuf\n");
874 			err++;
875 			m_freem(m);
876 			break;
877 		}
878 		m_copydata(m, sizeof(struct usie_desc) + pad, ipl, mtod(m0, caddr_t));
879 		m0->m_pkthdr.rcvif = ifp;
880 		m0->m_pkthdr.len = m0->m_len = ipl;
881 
882 		BPF_MTAP(sc->sc_ifp, m0);
883 		netisr_dispatch(ipv, m0);
884 
885 		m->m_data += diff;
886 		m->m_pkthdr.len = (m->m_len -= diff);
887 	}
888 
889 	mtx_lock(&sc->sc_mtx);
890 
891 	ifp->if_ierrors += err;
892 	ifp->if_ipackets += pkt;
893 }
894 
895 static void
896 usie_if_tx_callback(struct usb_xfer *xfer, usb_error_t error)
897 {
898 	struct usie_softc *sc = usbd_xfer_softc(xfer);
899 	struct usb_page_cache *pc;
900 	struct ifnet *ifp = sc->sc_ifp;
901 	struct mbuf *m;
902 	uint16_t size;
903 
904 	switch (USB_GET_STATE(xfer)) {
905 	case USB_ST_TRANSFERRED:
906 		DPRINTFN(11, "transfer complete\n");
907 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
908 		ifp->if_opackets++;
909 
910 		/* fall though */
911 	case USB_ST_SETUP:
912 tr_setup:
913 
914 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
915 			break;
916 
917 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
918 		if (m == NULL)
919 			break;
920 
921 		if (m->m_pkthdr.len > (MCLBYTES - ETHER_HDR_LEN +
922 		    ETHER_CRC_LEN - sizeof(sc->sc_txd))) {
923 			DPRINTF("packet len is too big: %d\n",
924 			    m->m_pkthdr.len);
925 			break;
926 		}
927 		pc = usbd_xfer_get_frame(xfer, 0);
928 
929 		sc->sc_txd.hip.len = htobe16(m->m_pkthdr.len +
930 		    ETHER_HDR_LEN + ETHER_CRC_LEN);
931 		size = sizeof(sc->sc_txd);
932 
933 		usbd_copy_in(pc, 0, &sc->sc_txd, size);
934 		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
935 		usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len +
936 		    size + ETHER_CRC_LEN);
937 
938 		BPF_MTAP(ifp, m);
939 
940 		m_freem(m);
941 
942 		usbd_transfer_submit(xfer);
943 		break;
944 
945 	default:			/* Error */
946 		DPRINTF("USB transfer error, %s\n",
947 		    usbd_errstr(error));
948 		ifp->if_oerrors++;
949 
950 		if (error != USB_ERR_CANCELLED) {
951 			usbd_xfer_set_stall(xfer);
952 			ifp->if_ierrors++;
953 			goto tr_setup;
954 		}
955 		break;
956 	}
957 }
958 
959 static void
960 usie_if_status_callback(struct usb_xfer *xfer, usb_error_t error)
961 {
962 	struct usie_softc *sc = usbd_xfer_softc(xfer);
963 	struct usb_page_cache *pc;
964 	struct usb_cdc_notification cdc;
965 	uint32_t actlen;
966 
967 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
968 
969 	switch (USB_GET_STATE(xfer)) {
970 	case USB_ST_TRANSFERRED:
971 		DPRINTFN(4, "info received, actlen=%d\n", actlen);
972 
973 		/* usb_cdc_notification - .data[16] */
974 		if (actlen < (sizeof(cdc) - 16)) {
975 			DPRINTF("data too short %d\n", actlen);
976 			goto tr_setup;
977 		}
978 		pc = usbd_xfer_get_frame(xfer, 0);
979 		usbd_copy_out(pc, 0, &cdc, (sizeof(cdc) - 16));
980 
981 		DPRINTFN(4, "bNotification=%x\n", cdc.bNotification);
982 
983 		if (cdc.bNotification & UCDC_N_RESPONSE_AVAILABLE) {
984 			taskqueue_enqueue(taskqueue_thread,
985 			    &sc->sc_if_status_task);
986 		}
987 		/* fall though */
988 	case USB_ST_SETUP:
989 tr_setup:
990 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
991 		usbd_transfer_submit(xfer);
992 		break;
993 
994 	default:			/* Error */
995 		DPRINTF("USB transfer error, %s\n",
996 		    usbd_errstr(error));
997 
998 		if (error != USB_ERR_CANCELLED) {
999 			usbd_xfer_set_stall(xfer);
1000 			goto tr_setup;
1001 		}
1002 		break;
1003 	}
1004 }
1005 
1006 static void
1007 usie_if_sync_to(void *arg)
1008 {
1009 	struct usie_softc *sc = arg;
1010 
1011 	taskqueue_enqueue(taskqueue_thread, &sc->sc_if_sync_task);
1012 }
1013 
1014 static void
1015 usie_if_sync_cb(void *arg, int pending)
1016 {
1017 	struct usie_softc *sc = arg;
1018 
1019 	mtx_lock(&sc->sc_mtx);
1020 
1021 	/* call twice */
1022 	usie_if_cmd(sc, USIE_HIP_SYNC2M);
1023 	usie_if_cmd(sc, USIE_HIP_SYNC2M);
1024 
1025 	usb_callout_reset(&sc->sc_if_sync_ch, 2 * hz, usie_if_sync_to, sc);
1026 
1027 	mtx_unlock(&sc->sc_mtx);
1028 }
1029 
1030 static void
1031 usie_if_status_cb(void *arg, int pending)
1032 {
1033 	struct usie_softc *sc = arg;
1034 	struct ifnet *ifp = sc->sc_ifp;
1035 	struct usb_device_request req;
1036 	struct usie_hip *hip;
1037 	struct usie_lsi *lsi;
1038 	uint16_t actlen;
1039 	uint8_t ntries;
1040 	uint8_t pad;
1041 
1042 	mtx_lock(&sc->sc_mtx);
1043 
1044 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
1045 	req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
1046 	USETW(req.wValue, 0);
1047 	USETW(req.wIndex, sc->sc_if_ifnum);
1048 	USETW(req.wLength, sizeof(sc->sc_status_temp));
1049 
1050 	for (ntries = 0; ntries != 10; ntries++) {
1051 		int err;
1052 
1053 		err = usbd_do_request_flags(sc->sc_udev,
1054 		    &sc->sc_mtx, &req, sc->sc_status_temp, USB_SHORT_XFER_OK,
1055 		    &actlen, USB_DEFAULT_TIMEOUT);
1056 
1057 		if (err == 0)
1058 			break;
1059 
1060 		DPRINTF("Control request failed: %s %d/10\n",
1061 		    usbd_errstr(err), ntries);
1062 
1063 		usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(10));
1064 	}
1065 
1066 	if (ntries == 10) {
1067 		mtx_unlock(&sc->sc_mtx);
1068 		DPRINTF("Timeout\n");
1069 		return;
1070 	}
1071 
1072 	hip = (struct usie_hip *)sc->sc_status_temp;
1073 
1074 	pad = (hip->id & USIE_HIP_PAD) ? 1 : 0;
1075 
1076 	DPRINTF("hip.id=%x hip.len=%d actlen=%u pad=%d\n",
1077 	    hip->id, be16toh(hip->len), actlen, pad);
1078 
1079 	switch (hip->id & USIE_HIP_MASK) {
1080 	case USIE_HIP_SYNC2H:
1081 		usie_if_cmd(sc, USIE_HIP_SYNC2M);
1082 		break;
1083 	case USIE_HIP_RESTR:
1084 		usb_callout_stop(&sc->sc_if_sync_ch);
1085 		break;
1086 	case USIE_HIP_UMTS:
1087 		lsi = (struct usie_lsi *)(
1088 		    sc->sc_status_temp + sizeof(struct usie_hip) + pad);
1089 
1090 		DPRINTF("lsi.proto=%x lsi.len=%d\n", lsi->proto,
1091 		    be16toh(lsi->len));
1092 
1093 		if (lsi->proto != USIE_LSI_UMTS)
1094 			break;
1095 
1096 		if (lsi->area == USIE_LSI_AREA_NO ||
1097 		    lsi->area == USIE_LSI_AREA_NODATA) {
1098 			device_printf(sc->sc_dev, "no service available\n");
1099 			break;
1100 		}
1101 		if (lsi->state == USIE_LSI_STATE_IDLE) {
1102 			DPRINTF("lsi.state=%x\n", lsi->state);
1103 			break;
1104 		}
1105 		DPRINTF("ctx=%x\n", hip->param);
1106 		sc->sc_txd.hip.param = hip->param;
1107 
1108 		sc->sc_net.addr_len = lsi->pdp_addr_len;
1109 		memcpy(&sc->sc_net.dns1_addr, &lsi->dns1_addr, 16);
1110 		memcpy(&sc->sc_net.dns2_addr, &lsi->dns2_addr, 16);
1111 		memcpy(sc->sc_net.pdp_addr, lsi->pdp_addr, 16);
1112 		memcpy(sc->sc_net.gw_addr, lsi->gw_addr, 16);
1113 		ifp->if_flags |= IFF_UP;
1114 		ifp->if_drv_flags |= IFF_DRV_RUNNING;
1115 
1116 		device_printf(sc->sc_dev, "IP Addr=%d.%d.%d.%d\n",
1117 		    *lsi->pdp_addr, *(lsi->pdp_addr + 1),
1118 		    *(lsi->pdp_addr + 2), *(lsi->pdp_addr + 3));
1119 		device_printf(sc->sc_dev, "Gateway Addr=%d.%d.%d.%d\n",
1120 		    *lsi->gw_addr, *(lsi->gw_addr + 1),
1121 		    *(lsi->gw_addr + 2), *(lsi->gw_addr + 3));
1122 		device_printf(sc->sc_dev, "Prim NS Addr=%d.%d.%d.%d\n",
1123 		    *lsi->dns1_addr, *(lsi->dns1_addr + 1),
1124 		    *(lsi->dns1_addr + 2), *(lsi->dns1_addr + 3));
1125 		device_printf(sc->sc_dev, "Scnd NS Addr=%d.%d.%d.%d\n",
1126 		    *lsi->dns2_addr, *(lsi->dns2_addr + 1),
1127 		    *(lsi->dns2_addr + 2), *(lsi->dns2_addr + 3));
1128 
1129 		usie_cns_req(sc, USIE_CNS_ID_RSSI, USIE_CNS_OB_RSSI);
1130 		break;
1131 
1132 	case USIE_HIP_RCGI:
1133 		/* ignore, workaround for sloppy windows */
1134 		break;
1135 	default:
1136 		DPRINTF("undefined msgid: %x\n", hip->id);
1137 		break;
1138 	}
1139 
1140 	mtx_unlock(&sc->sc_mtx);
1141 }
1142 
1143 static void
1144 usie_if_start(struct ifnet *ifp)
1145 {
1146 	struct usie_softc *sc = ifp->if_softc;
1147 
1148 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1149 		DPRINTF("Not running\n");
1150 		return;
1151 	}
1152 	mtx_lock(&sc->sc_mtx);
1153 	usbd_transfer_start(sc->sc_if_xfer[USIE_IF_TX]);
1154 	mtx_unlock(&sc->sc_mtx);
1155 
1156 	DPRINTFN(3, "interface started\n");
1157 }
1158 
1159 static int
1160 usie_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1161     struct route *ro)
1162 {
1163 	int err;
1164 
1165 	DPRINTF("proto=%x\n", dst->sa_family);
1166 
1167 	switch (dst->sa_family) {
1168 #ifdef INET6
1169 	case AF_INET6;
1170 	/* fall though */
1171 #endif
1172 	case AF_INET:
1173 		break;
1174 
1175 		/* silently drop dhclient packets */
1176 	case AF_UNSPEC:
1177 		m_freem(m);
1178 		return (0);
1179 
1180 		/* drop other packet types */
1181 	default:
1182 		m_freem(m);
1183 		return (EAFNOSUPPORT);
1184 	}
1185 
1186 	err = (ifp->if_transmit)(ifp, m);
1187 	if (err) {
1188 		ifp->if_oerrors++;
1189 		return (ENOBUFS);
1190 	}
1191 	ifp->if_opackets++;
1192 
1193 	return (0);
1194 }
1195 
1196 static void
1197 usie_if_init(void *arg)
1198 {
1199 	struct usie_softc *sc = arg;
1200 	struct ifnet *ifp = sc->sc_ifp;
1201 	uint8_t i;
1202 
1203 	mtx_lock(&sc->sc_mtx);
1204 
1205 	/* write tx descriptor */
1206 	sc->sc_txd.hip.id = USIE_HIP_CTX;
1207 	sc->sc_txd.hip.param = 0;	/* init value */
1208 	sc->sc_txd.desc_type = htobe16(USIE_IP_TX);
1209 
1210 	for (i = 0; i != USIE_IF_N_XFER; i++)
1211 		usbd_xfer_set_stall(sc->sc_if_xfer[i]);
1212 
1213 	usbd_transfer_start(sc->sc_uc_xfer[USIE_HIP_IF][USIE_UC_RX]);
1214 	usbd_transfer_start(sc->sc_if_xfer[USIE_IF_STATUS]);
1215 	usbd_transfer_start(sc->sc_if_xfer[USIE_IF_RX]);
1216 
1217 	/* if not running, initiate the modem */
1218 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
1219 		usie_cns_req(sc, USIE_CNS_ID_INIT, USIE_CNS_OB_LINK_UPDATE);
1220 
1221 	mtx_unlock(&sc->sc_mtx);
1222 
1223 	DPRINTF("ifnet initialized\n");
1224 }
1225 
1226 static void
1227 usie_if_stop(struct usie_softc *sc)
1228 {
1229 	usb_callout_drain(&sc->sc_if_sync_ch);
1230 
1231 	mtx_lock(&sc->sc_mtx);
1232 
1233 	/* usie_cns_req() clears IFF_* flags */
1234 	usie_cns_req(sc, USIE_CNS_ID_STOP, USIE_CNS_OB_LINK_UPDATE);
1235 
1236 	usbd_transfer_stop(sc->sc_if_xfer[USIE_IF_TX]);
1237 	usbd_transfer_stop(sc->sc_if_xfer[USIE_IF_RX]);
1238 	usbd_transfer_stop(sc->sc_if_xfer[USIE_IF_STATUS]);
1239 
1240 	/* shutdown device */
1241 	usie_if_cmd(sc, USIE_HIP_DOWN);
1242 
1243 	mtx_unlock(&sc->sc_mtx);
1244 }
1245 
1246 static int
1247 usie_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1248 {
1249 	struct usie_softc *sc = ifp->if_softc;
1250 	struct ieee80211req *ireq;
1251 	struct ieee80211req_sta_info si;
1252 	struct ifmediareq *ifmr;
1253 
1254 	switch (cmd) {
1255 	case SIOCSIFFLAGS:
1256 		if (ifp->if_flags & IFF_UP) {
1257 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
1258 				usie_if_init(sc);
1259 		} else {
1260 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1261 				usie_if_stop(sc);
1262 		}
1263 		break;
1264 
1265 	case SIOCSIFCAP:
1266 		if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1267 			device_printf(sc->sc_dev,
1268 			    "Connect to the network first.\n");
1269 			break;
1270 		}
1271 		mtx_lock(&sc->sc_mtx);
1272 		usie_cns_req(sc, USIE_CNS_ID_RSSI, USIE_CNS_OB_RSSI);
1273 		mtx_unlock(&sc->sc_mtx);
1274 		break;
1275 
1276 	case SIOCG80211:
1277 		ireq = (struct ieee80211req *)data;
1278 
1279 		if (ireq->i_type != IEEE80211_IOC_STA_INFO)
1280 			break;
1281 
1282 		memset(&si, 0, sizeof(si));
1283 		si.isi_len = sizeof(si);
1284 		/*
1285 		 * ifconfig expects RSSI in 0.5dBm units
1286 		 * relative to the noise floor.
1287 		 */
1288 		si.isi_rssi = 2 * sc->sc_rssi;
1289 		if (copyout(&si, (uint8_t *)ireq->i_data + 8,
1290 		    sizeof(struct ieee80211req_sta_info)))
1291 			DPRINTF("copyout failed\n");
1292 		DPRINTF("80211\n");
1293 		break;
1294 
1295 	case SIOCGIFMEDIA:		/* to fool ifconfig */
1296 		ifmr = (struct ifmediareq *)data;
1297 		ifmr->ifm_count = 1;
1298 		DPRINTF("media\n");
1299 		break;
1300 
1301 	case SIOCSIFADDR:
1302 	case SIOCSIFDSTADDR:
1303 		break;
1304 
1305 	default:
1306 		return (EINVAL);
1307 	}
1308 	return (0);
1309 }
1310 
1311 static int
1312 usie_do_request(struct usie_softc *sc, struct usb_device_request *req,
1313     void *data)
1314 {
1315 	int err = 0;
1316 	int ntries;
1317 
1318 	mtx_assert(&sc->sc_mtx, MA_OWNED);
1319 
1320 	for (ntries = 0; ntries != 10; ntries++) {
1321 		err = usbd_do_request(sc->sc_udev,
1322 		    &sc->sc_mtx, req, data);
1323 		if (err == 0)
1324 			break;
1325 
1326 		DPRINTF("Control request failed: %s %d/10\n",
1327 		    usbd_errstr(err), ntries);
1328 
1329 		usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(10));
1330 	}
1331 	return (err);
1332 }
1333 
1334 static int
1335 usie_if_cmd(struct usie_softc *sc, uint8_t cmd)
1336 {
1337 	struct usb_device_request req;
1338 	struct usie_hip msg;
1339 
1340 	msg.len = 0;
1341 	msg.id = cmd;
1342 	msg.param = 0;
1343 
1344 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1345 	req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
1346 	USETW(req.wValue, 0);
1347 	USETW(req.wIndex, sc->sc_if_ifnum);
1348 	USETW(req.wLength, sizeof(msg));
1349 
1350 	DPRINTF("cmd=%x\n", cmd);
1351 
1352 	return (usie_do_request(sc, &req, &msg));
1353 }
1354 
1355 static void
1356 usie_cns_req(struct usie_softc *sc, uint32_t id, uint16_t obj)
1357 {
1358 	struct ifnet *ifp = sc->sc_ifp;
1359 	struct mbuf *m;
1360 	struct usb_xfer *xfer;
1361 	struct usie_hip *hip;
1362 	struct usie_cns *cns;
1363 	uint8_t *param;
1364 	uint8_t *tmp;
1365 	uint8_t cns_len;
1366 
1367 	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1368 	if (__predict_false(m == NULL)) {
1369 		DPRINTF("could not allocate mbuf\n");
1370 		ifp->if_ierrors++;
1371 		return;
1372 	}
1373 	/* to align usie_hip{} on 32 bit */
1374 	m->m_data += 3;
1375 	param = mtod(m, uint8_t *);
1376 	*param++ = USIE_HIP_FRM_CHR;
1377 	hip = (struct usie_hip *)param;
1378 	cns = (struct usie_cns *)(hip + 1);
1379 
1380 	tmp = param + USIE_HIPCNS_MIN - 2;
1381 
1382 	switch (obj) {
1383 	case USIE_CNS_OB_LINK_UPDATE:
1384 		cns_len = 2;
1385 		cns->op = USIE_CNS_OP_SET;
1386 		*tmp++ = 1;		/* profile ID, always use 1 for now */
1387 		*tmp++ = id == USIE_CNS_ID_INIT ? 1 : 0;
1388 		break;
1389 
1390 	case USIE_CNS_OB_PROF_WRITE:
1391 		cns_len = 245;
1392 		cns->op = USIE_CNS_OP_SET;
1393 		*tmp++ = 1;		/* profile ID, always use 1 for now */
1394 		*tmp++ = 2;
1395 		memcpy(tmp, &sc->sc_net, 34);
1396 		memset(tmp + 35, 0, 245 - 36);
1397 		tmp += 243;
1398 		break;
1399 
1400 	case USIE_CNS_OB_RSSI:
1401 		cns_len = 0;
1402 		cns->op = USIE_CNS_OP_REQ;
1403 		break;
1404 
1405 	default:
1406 		DPRINTF("unsupported CnS object type\n");
1407 		return;
1408 	}
1409 	*tmp = USIE_HIP_FRM_CHR;
1410 
1411 	hip->len = htobe16(sizeof(struct usie_cns) + cns_len);
1412 	hip->id = USIE_HIP_CNS2M;
1413 	hip->param = 0;			/* none for CnS */
1414 
1415 	cns->obj = htobe16(obj);
1416 	cns->id = htobe32(id);
1417 	cns->len = cns_len;
1418 	cns->rsv0 = cns->rsv1 = 0;	/* always '0' */
1419 
1420 	param = (uint8_t *)(cns + 1);
1421 
1422 	DPRINTF("param: %16D\n", param, ":");
1423 
1424 	m->m_pkthdr.len = m->m_len = USIE_HIPCNS_MIN + cns_len + 2;
1425 
1426 	xfer = sc->sc_uc_xfer[USIE_HIP_IF][USIE_UC_TX];
1427 
1428 	if (usbd_xfer_get_priv(xfer) == NULL) {
1429 		usbd_xfer_set_priv(xfer, m);
1430 		usbd_transfer_start(xfer);
1431 	} else {
1432 		DPRINTF("Dropped CNS event\n");
1433 		m_freem(m);
1434 	}
1435 }
1436 
1437 static void
1438 usie_cns_rsp(struct usie_softc *sc, struct usie_cns *cns)
1439 {
1440 	struct ifnet *ifp = sc->sc_ifp;
1441 
1442 	DPRINTF("received CnS\n");
1443 
1444 	switch (be16toh(cns->obj)) {
1445 	case USIE_CNS_OB_LINK_UPDATE:
1446 		if (be32toh(cns->id) & USIE_CNS_ID_INIT)
1447 			usie_if_sync_to(sc);
1448 		else if (be32toh(cns->id) & USIE_CNS_ID_STOP) {
1449 			ifp->if_flags &= ~IFF_UP;
1450 			ifp->if_drv_flags &=
1451 			    ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1452 		} else
1453 			DPRINTF("undefined link update\n");
1454 		break;
1455 
1456 	case USIE_CNS_OB_RSSI:
1457 		sc->sc_rssi = be16toh(*(int16_t *)(cns + 1));
1458 		if (sc->sc_rssi <= 0)
1459 			device_printf(sc->sc_dev, "No signal\n");
1460 		else {
1461 			device_printf(sc->sc_dev, "RSSI=%ddBm\n",
1462 			    sc->sc_rssi - 110);
1463 		}
1464 		break;
1465 
1466 	case USIE_CNS_OB_PROF_WRITE:
1467 		break;
1468 
1469 	case USIE_CNS_OB_PDP_READ:
1470 		break;
1471 
1472 	default:
1473 		DPRINTF("undefined CnS\n");
1474 		break;
1475 	}
1476 }
1477 
1478 static void
1479 usie_hip_rsp(struct usie_softc *sc, uint8_t *rsp, uint32_t len)
1480 {
1481 	struct usie_hip *hip;
1482 	struct usie_cns *cns;
1483 	uint32_t i;
1484 	uint32_t j;
1485 	uint32_t off;
1486 	uint8_t tmp[USIE_HIPCNS_MAX] __aligned(4);
1487 
1488 	for (off = 0; (off + USIE_HIPCNS_MIN) <= len; off++) {
1489 
1490 		uint8_t pad;
1491 
1492 		while ((off < len) && (rsp[off] == USIE_HIP_FRM_CHR))
1493 			off++;
1494 
1495 		/* Unstuff the bytes */
1496 		for (i = j = 0; ((i + off) < len) &&
1497 		    (j < USIE_HIPCNS_MAX); i++) {
1498 
1499 			if (rsp[i + off] == USIE_HIP_FRM_CHR)
1500 				break;
1501 
1502 			if (rsp[i + off] == USIE_HIP_ESC_CHR) {
1503 				if ((i + off + 1) >= len)
1504 					break;
1505 				tmp[j++] = rsp[i++ + off + 1] ^ 0x20;
1506 			} else {
1507 				tmp[j++] = rsp[i + off];
1508 			}
1509 		}
1510 
1511 		off += i;
1512 
1513 		DPRINTF("frame len=%d\n", j);
1514 
1515 		if (j < sizeof(struct usie_hip)) {
1516 			DPRINTF("too little data\n");
1517 			break;
1518 		}
1519 		/*
1520 		 * Make sure we are not reading the stack if something
1521 		 * is wrong.
1522 		 */
1523 		memset(tmp + j, 0, sizeof(tmp) - j);
1524 
1525 		hip = (struct usie_hip *)tmp;
1526 
1527 		DPRINTF("hip: len=%d msgID=%02x, param=%02x\n",
1528 		    be16toh(hip->len), hip->id, hip->param);
1529 
1530 		pad = (hip->id & USIE_HIP_PAD) ? 1 : 0;
1531 
1532 		if ((hip->id & USIE_HIP_MASK) == USIE_HIP_CNS2H) {
1533 			cns = (struct usie_cns *)(((uint8_t *)(hip + 1)) + pad);
1534 
1535 			if (j < (sizeof(struct usie_cns) +
1536 			    sizeof(struct usie_hip) + pad)) {
1537 				DPRINTF("too little data\n");
1538 				break;
1539 			}
1540 			DPRINTF("cns: obj=%04x, op=%02x, rsv0=%02x, "
1541 			    "app=%08x, rsv1=%02x, len=%d\n",
1542 			    be16toh(cns->obj), cns->op, cns->rsv0,
1543 			    be32toh(cns->id), cns->rsv1, cns->len);
1544 
1545 			if (cns->op & USIE_CNS_OP_ERR)
1546 				DPRINTF("CnS error response\n");
1547 			else
1548 				usie_cns_rsp(sc, cns);
1549 
1550 			i = sizeof(struct usie_hip) + pad + sizeof(struct usie_cns);
1551 			j = cns->len;
1552 		} else {
1553 			i = sizeof(struct usie_hip) + pad;
1554 			j = be16toh(hip->len);
1555 		}
1556 #ifdef	USB_DEBUG
1557 		if (usie_debug == 0)
1558 			continue;
1559 
1560 		while (i < USIE_HIPCNS_MAX && j > 0) {
1561 			DPRINTF("param[0x%02x] = 0x%02x\n", i, tmp[i]);
1562 			i++;
1563 			j--;
1564 		}
1565 #endif
1566 	}
1567 }
1568 
1569 static int
1570 usie_driver_loaded(struct module *mod, int what, void *arg)
1571 {
1572 	switch (what) {
1573 	case MOD_LOAD:
1574 		/* register autoinstall handler */
1575 		usie_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
1576 		    usie_autoinst, NULL, EVENTHANDLER_PRI_ANY);
1577 		break;
1578 	case MOD_UNLOAD:
1579 		EVENTHANDLER_DEREGISTER(usb_dev_configured, usie_etag);
1580 		break;
1581 	default:
1582 		return (EOPNOTSUPP);
1583 	}
1584 	return (0);
1585 }
1586 
1587