1f9f848faSopenharmony_ci/*	$OpenBSD: if_urndis.c,v 1.46 2013/12/09 15:45:29 pirofti Exp $ */
2f9f848faSopenharmony_ci
3f9f848faSopenharmony_ci/*
4f9f848faSopenharmony_ci * Copyright (c) 2010 Jonathan Armani <armani@openbsd.org>
5f9f848faSopenharmony_ci * Copyright (c) 2010 Fabien Romano <fabien@openbsd.org>
6f9f848faSopenharmony_ci * Copyright (c) 2010 Michael Knudsen <mk@openbsd.org>
7f9f848faSopenharmony_ci * Copyright (c) 2014 Hans Petter Selasky <hselasky@freebsd.org>
8f9f848faSopenharmony_ci * All rights reserved.
9f9f848faSopenharmony_ci *
10f9f848faSopenharmony_ci * Permission to use, copy, modify, and distribute this software for any
11f9f848faSopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
12f9f848faSopenharmony_ci * copyright notice and this permission notice appear in all copies.
13f9f848faSopenharmony_ci *
14f9f848faSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15f9f848faSopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16f9f848faSopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17f9f848faSopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18f9f848faSopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19f9f848faSopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20f9f848faSopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21f9f848faSopenharmony_ci */
22f9f848faSopenharmony_ci
23f9f848faSopenharmony_ci#include <sys/cdefs.h>
24f9f848faSopenharmony_ci
25f9f848faSopenharmony_ci#include <lwip/netif.h>
26f9f848faSopenharmony_ci#include <lwip/dhcp.h>
27f9f848faSopenharmony_ci#include <lwip/netifapi.h>
28f9f848faSopenharmony_ci#include <lwip/inet.h>
29f9f848faSopenharmony_ci
30f9f848faSopenharmony_ci#include "if_urndisreg.h"
31f9f848faSopenharmony_ci
32f9f848faSopenharmony_cistatic device_probe_t urndis_probe;
33f9f848faSopenharmony_cistatic device_attach_t urndis_attach;
34f9f848faSopenharmony_cistatic device_detach_t urndis_detach;
35f9f848faSopenharmony_cistatic device_suspend_t urndis_suspend;
36f9f848faSopenharmony_cistatic device_resume_t urndis_resume;
37f9f848faSopenharmony_ci
38f9f848faSopenharmony_cistatic usb_callback_t urndis_bulk_write_callback;
39f9f848faSopenharmony_cistatic usb_callback_t urndis_bulk_read_callback;
40f9f848faSopenharmony_cistatic usb_callback_t urndis_intr_read_callback;
41f9f848faSopenharmony_ci
42f9f848faSopenharmony_cistatic uether_fn_t urndis_attach_post;
43f9f848faSopenharmony_cistatic uether_fn_t urndis_init;
44f9f848faSopenharmony_cistatic uether_fn_t urndis_stop;
45f9f848faSopenharmony_cistatic uether_fn_t urndis_start;
46f9f848faSopenharmony_cistatic uether_fn_t urndis_setmulti;
47f9f848faSopenharmony_cistatic uether_fn_t urndis_setpromisc;
48f9f848faSopenharmony_ci
49f9f848faSopenharmony_cistatic uint32_t urndis_ctrl_query(struct urndis_softc *sc, uint32_t oid,
50f9f848faSopenharmony_ci		    struct urndis_query_req *msg, uint16_t len,
51f9f848faSopenharmony_ci		    const void **rbuf, uint16_t *rbufsz);
52f9f848faSopenharmony_cistatic uint32_t urndis_ctrl_set(struct urndis_softc *sc, uint32_t oid,
53f9f848faSopenharmony_ci		    struct urndis_set_req *msg, uint16_t len);
54f9f848faSopenharmony_cistatic uint32_t urndis_ctrl_handle_init(struct urndis_softc *sc,
55f9f848faSopenharmony_ci		    const struct urndis_comp_hdr *hdr);
56f9f848faSopenharmony_cistatic uint32_t urndis_ctrl_handle_query(struct urndis_softc *sc,
57f9f848faSopenharmony_ci		    const struct urndis_comp_hdr *hdr, const void **buf,
58f9f848faSopenharmony_ci		    uint16_t *bufsz);
59f9f848faSopenharmony_cistatic uint32_t urndis_ctrl_handle_reset(struct urndis_softc *sc,
60f9f848faSopenharmony_ci		    const struct urndis_comp_hdr *hdr);
61f9f848faSopenharmony_cistatic uint32_t urndis_ctrl_init(struct urndis_softc *sc);
62f9f848faSopenharmony_cistatic uint32_t urndis_ctrl_halt(struct urndis_softc *sc);
63f9f848faSopenharmony_ci
64f9f848faSopenharmony_ci#undef USB_DEBUG_VAR
65f9f848faSopenharmony_ci#define	USB_DEBUG_VAR   urndis_debug
66f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG
67f9f848faSopenharmony_cistatic int urndis_debug = 0;
68f9f848faSopenharmony_civoid
69f9f848faSopenharmony_ciusb_urndis_debug_func(int level)
70f9f848faSopenharmony_ci{
71f9f848faSopenharmony_ci	urndis_debug = level;
72f9f848faSopenharmony_ci	PRINTK("The level of usb urndis debug is %d\n", level);
73f9f848faSopenharmony_ci}
74f9f848faSopenharmony_ciDEBUG_MODULE(urndis, usb_urndis_debug_func);
75f9f848faSopenharmony_ci#endif
76f9f848faSopenharmony_ci
77f9f848faSopenharmony_cistatic const struct usb_config urndis_config[URNDIS_N_TRANSFER] = {
78f9f848faSopenharmony_ci	{ /* [URNDIS_BULK_RX] = */
79f9f848faSopenharmony_ci		.type = UE_BULK,
80f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
81f9f848faSopenharmony_ci		.direction = UE_DIR_RX,
82f9f848faSopenharmony_ci		.if_index = 0,
83f9f848faSopenharmony_ci		.frames = 1,
84f9f848faSopenharmony_ci		.bufsize = RNDIS_RX_MAXLEN,
85f9f848faSopenharmony_ci		.flags = {.short_xfer_ok = 1,},
86f9f848faSopenharmony_ci		.callback = urndis_bulk_read_callback,
87f9f848faSopenharmony_ci		.timeout = 0,		/* no timeout */
88f9f848faSopenharmony_ci		.usb_mode = USB_MODE_HOST,
89f9f848faSopenharmony_ci	},
90f9f848faSopenharmony_ci
91f9f848faSopenharmony_ci	{ /* [URNDIS_BULK_TX] = */
92f9f848faSopenharmony_ci		.type = UE_BULK,
93f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
94f9f848faSopenharmony_ci		.direction = UE_DIR_TX,
95f9f848faSopenharmony_ci		.if_index = 0,
96f9f848faSopenharmony_ci		.frames = RNDIS_TX_FRAMES_MAX,
97f9f848faSopenharmony_ci		.bufsize = (RNDIS_TX_FRAMES_MAX * RNDIS_TX_MAXLEN),
98f9f848faSopenharmony_ci		.flags = {
99f9f848faSopenharmony_ci			.force_short_xfer = 1,
100f9f848faSopenharmony_ci		},
101f9f848faSopenharmony_ci		.callback = urndis_bulk_write_callback,
102f9f848faSopenharmony_ci		.timeout = 10000,	/* 10 seconds */
103f9f848faSopenharmony_ci		.usb_mode = USB_MODE_HOST,
104f9f848faSopenharmony_ci	},
105f9f848faSopenharmony_ci
106f9f848faSopenharmony_ci	{ /* [URNDIS_INTR_RX] = */
107f9f848faSopenharmony_ci		.type = UE_INTERRUPT,
108f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
109f9f848faSopenharmony_ci		.direction = UE_DIR_RX,
110f9f848faSopenharmony_ci		.if_index = 1,
111f9f848faSopenharmony_ci		.bufsize = 0,	/* use wMaxPacketSize */
112f9f848faSopenharmony_ci		.flags = {.short_xfer_ok = 1,.no_pipe_ok = 1,},
113f9f848faSopenharmony_ci		.callback = urndis_intr_read_callback,
114f9f848faSopenharmony_ci		.timeout = 0,
115f9f848faSopenharmony_ci		.usb_mode = USB_MODE_HOST,
116f9f848faSopenharmony_ci	},
117f9f848faSopenharmony_ci};
118f9f848faSopenharmony_ci
119f9f848faSopenharmony_cistatic device_method_t urndis_methods[] = {
120f9f848faSopenharmony_ci	/* Device interface */
121f9f848faSopenharmony_ci	DEVMETHOD(device_probe, urndis_probe),
122f9f848faSopenharmony_ci	DEVMETHOD(device_attach, urndis_attach),
123f9f848faSopenharmony_ci	DEVMETHOD(device_detach, urndis_detach),
124f9f848faSopenharmony_ci	DEVMETHOD(device_suspend, urndis_suspend),
125f9f848faSopenharmony_ci	DEVMETHOD(device_resume, urndis_resume),
126f9f848faSopenharmony_ci
127f9f848faSopenharmony_ci	DEVMETHOD_END
128f9f848faSopenharmony_ci};
129f9f848faSopenharmony_ci
130f9f848faSopenharmony_cistatic driver_t urndis_driver = {
131f9f848faSopenharmony_ci	.name = "urndis",
132f9f848faSopenharmony_ci	.methods = urndis_methods,
133f9f848faSopenharmony_ci	.size = sizeof(struct urndis_softc),
134f9f848faSopenharmony_ci};
135f9f848faSopenharmony_ci
136f9f848faSopenharmony_cistatic devclass_t urndis_devclass;
137f9f848faSopenharmony_ci
138f9f848faSopenharmony_ciDRIVER_MODULE(urndis, uhub, urndis_driver, urndis_devclass, NULL, NULL);
139f9f848faSopenharmony_ci
140f9f848faSopenharmony_cistatic const struct usb_ether_methods urndis_ue_methods = {
141f9f848faSopenharmony_ci	.ue_attach_post = urndis_attach_post,
142f9f848faSopenharmony_ci	.ue_start = urndis_start,
143f9f848faSopenharmony_ci	.ue_init = urndis_init,
144f9f848faSopenharmony_ci	.ue_stop = urndis_stop,
145f9f848faSopenharmony_ci	.ue_setmulti = urndis_setmulti,
146f9f848faSopenharmony_ci	.ue_setpromisc = urndis_setpromisc,
147f9f848faSopenharmony_ci};
148f9f848faSopenharmony_ci
149f9f848faSopenharmony_cistatic const STRUCT_USB_HOST_ID urndis_host_devs[] = {
150f9f848faSopenharmony_ci	/* Generic RNDIS class match */
151f9f848faSopenharmony_ci	{USB_IFACE_CLASS(UICLASS_CDC),
152f9f848faSopenharmony_ci		USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL),
153f9f848faSopenharmony_ci		USB_IFACE_PROTOCOL(0xff)},
154f9f848faSopenharmony_ci	{USB_IFACE_CLASS(UICLASS_WIRELESS), USB_IFACE_SUBCLASS(UISUBCLASS_RF),
155f9f848faSopenharmony_ci		USB_IFACE_PROTOCOL(UIPROTO_RNDIS)},
156f9f848faSopenharmony_ci	{USB_IFACE_CLASS(UICLASS_IAD), USB_IFACE_SUBCLASS(UISUBCLASS_SYNC),
157f9f848faSopenharmony_ci		USB_IFACE_PROTOCOL(UIPROTO_ACTIVESYNC)},
158f9f848faSopenharmony_ci};
159f9f848faSopenharmony_ci
160f9f848faSopenharmony_cistatic int
161f9f848faSopenharmony_ciurndis_probe(device_t dev)
162f9f848faSopenharmony_ci{
163f9f848faSopenharmony_ci	struct usb_attach_arg *uaa = device_get_ivars(dev);
164f9f848faSopenharmony_ci
165f9f848faSopenharmony_ci	return (usbd_lookup_id_by_uaa(urndis_host_devs, sizeof(urndis_host_devs), uaa));
166f9f848faSopenharmony_ci}
167f9f848faSopenharmony_ci
168f9f848faSopenharmony_cistatic void
169f9f848faSopenharmony_ciurndis_attach_post(struct usb_ether *ue)
170f9f848faSopenharmony_ci{
171f9f848faSopenharmony_ci	/* no-op */
172f9f848faSopenharmony_ci}
173f9f848faSopenharmony_ci
174f9f848faSopenharmony_cistatic int
175f9f848faSopenharmony_ciurndis_attach(device_t dev)
176f9f848faSopenharmony_ci{
177f9f848faSopenharmony_ci	static struct {
178f9f848faSopenharmony_ci		union {
179f9f848faSopenharmony_ci			struct urndis_query_req query;
180f9f848faSopenharmony_ci			struct urndis_set_req set;
181f9f848faSopenharmony_ci		} hdr;
182f9f848faSopenharmony_ci		union {
183f9f848faSopenharmony_ci			uint8_t eaddr[NETIF_MAX_HWADDR_LEN];
184f9f848faSopenharmony_ci			uint32_t filter;
185f9f848faSopenharmony_ci		} ibuf;
186f9f848faSopenharmony_ci	} msg;
187f9f848faSopenharmony_ci	struct urndis_softc *sc = device_get_softc(dev);
188f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
189f9f848faSopenharmony_ci	struct usb_attach_arg *uaa = device_get_ivars(dev);
190f9f848faSopenharmony_ci	struct usb_cdc_cm_descriptor *cmd;
191f9f848faSopenharmony_ci	const void *buf;
192f9f848faSopenharmony_ci	struct netif *netif;
193f9f848faSopenharmony_ci
194f9f848faSopenharmony_ci	uint16_t bufsz;
195f9f848faSopenharmony_ci	uint8_t iface_index[2] = {0};
196f9f848faSopenharmony_ci	int error;
197f9f848faSopenharmony_ci	uint8_t i;
198f9f848faSopenharmony_ci
199f9f848faSopenharmony_ci	sc->sc_ue.ue_udev = uaa->device;
200f9f848faSopenharmony_ci	sc->sc_ifaceno_ctl = uaa->info.bIfaceNum;
201f9f848faSopenharmony_ci	iface_index[0] = uaa->info.bIfaceIndex + 1;
202f9f848faSopenharmony_ci	iface_index[1] = uaa->info.bIfaceIndex;
203f9f848faSopenharmony_ci
204f9f848faSopenharmony_ci	cmd = usbd_find_descriptor(uaa->device, NULL, uaa->info.bIfaceIndex,
205f9f848faSopenharmony_ci		UDESC_CS_INTERFACE, 0xFF, UDESCSUB_CDC_CM, 0xFF);
206f9f848faSopenharmony_ci	if (cmd != 0) {
207f9f848faSopenharmony_ci		DPRINTF("Call Mode Descriptor found, dataif=%d\n", cmd->bDataInterface);
208f9f848faSopenharmony_ci		iface_index[0] = cmd->bDataInterface;
209f9f848faSopenharmony_ci	}
210f9f848faSopenharmony_ci
211f9f848faSopenharmony_ci	device_set_usb_desc(dev);
212f9f848faSopenharmony_ci
213f9f848faSopenharmony_ci	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_RECURSE);
214f9f848faSopenharmony_ci
215f9f848faSopenharmony_ci	/* scan the alternate settings looking for a valid one */
216f9f848faSopenharmony_ci	for (i = 0; i != 32; i++) {
217f9f848faSopenharmony_ci		error = usbd_set_alt_interface_index(uaa->device,
218f9f848faSopenharmony_ci		    iface_index[0], i);
219f9f848faSopenharmony_ci
220f9f848faSopenharmony_ci		if (error != 0)
221f9f848faSopenharmony_ci			break;
222f9f848faSopenharmony_ci
223f9f848faSopenharmony_ci		error = usbd_transfer_setup(uaa->device,
224f9f848faSopenharmony_ci		    iface_index, sc->sc_xfer, urndis_config,
225f9f848faSopenharmony_ci		    URNDIS_N_TRANSFER, sc, &sc->sc_mtx);
226f9f848faSopenharmony_ci
227f9f848faSopenharmony_ci		if (error == 0)
228f9f848faSopenharmony_ci			break;
229f9f848faSopenharmony_ci	}
230f9f848faSopenharmony_ci	if ((error != 0) || (i == 32)) {
231f9f848faSopenharmony_ci		device_printf(dev, "No valid alternate setting found\n");
232f9f848faSopenharmony_ci		goto detach;
233f9f848faSopenharmony_ci	}
234f9f848faSopenharmony_ci
235f9f848faSopenharmony_ci	URNDIS_LOCK(sc);
236f9f848faSopenharmony_ci	/* start interrupt endpoint, if any */
237f9f848faSopenharmony_ci	usbd_transfer_start(sc->sc_xfer[URNDIS_INTR_RX]);
238f9f848faSopenharmony_ci	URNDIS_UNLOCK(sc);
239f9f848faSopenharmony_ci
240f9f848faSopenharmony_ci	/* Initialize device - must be done before even querying it */
241f9f848faSopenharmony_ci	URNDIS_LOCK(sc);
242f9f848faSopenharmony_ci	error = urndis_ctrl_init(sc);
243f9f848faSopenharmony_ci	URNDIS_UNLOCK(sc);
244f9f848faSopenharmony_ci	if (error != (int)RNDIS_STATUS_SUCCESS) {
245f9f848faSopenharmony_ci		device_printf(dev, "Unable to initialize hardware\n");
246f9f848faSopenharmony_ci		goto detach;
247f9f848faSopenharmony_ci	}
248f9f848faSopenharmony_ci
249f9f848faSopenharmony_ci	/* Determine MAC address */
250f9f848faSopenharmony_ci	(void)memset_s(msg.ibuf.eaddr, sizeof(msg.ibuf.eaddr), 0, sizeof(msg.ibuf.eaddr));
251f9f848faSopenharmony_ci	URNDIS_LOCK(sc);
252f9f848faSopenharmony_ci	error = urndis_ctrl_query(sc, OID_802_3_PERMANENT_ADDRESS,
253f9f848faSopenharmony_ci	    &msg.hdr.query, sizeof(msg.hdr.query) + sizeof(msg.ibuf.eaddr),
254f9f848faSopenharmony_ci	    &buf, &bufsz);
255f9f848faSopenharmony_ci	URNDIS_UNLOCK(sc);
256f9f848faSopenharmony_ci	if (error != (int)RNDIS_STATUS_SUCCESS) {
257f9f848faSopenharmony_ci		device_printf(dev, "Unable to get hardware address\n");
258f9f848faSopenharmony_ci		goto detach;
259f9f848faSopenharmony_ci	}
260f9f848faSopenharmony_ci	if (bufsz != NETIF_MAX_HWADDR_LEN) {
261f9f848faSopenharmony_ci		device_printf(dev, "Invalid address length: %d bytes\n", bufsz);
262f9f848faSopenharmony_ci		goto detach;
263f9f848faSopenharmony_ci	}
264f9f848faSopenharmony_ci	(void)memcpy_s(&sc->sc_ue.ue_eaddr, NETIF_MAX_HWADDR_LEN, buf, NETIF_MAX_HWADDR_LEN);
265f9f848faSopenharmony_ci
266f9f848faSopenharmony_ci	/* Initialize packet filter */
267f9f848faSopenharmony_ci	sc->sc_filter = RNDIS_PACKET_TYPE_BROADCAST |
268f9f848faSopenharmony_ci	    RNDIS_PACKET_TYPE_ALL_MULTICAST;
269f9f848faSopenharmony_ci	msg.ibuf.filter = htole32(sc->sc_filter);
270f9f848faSopenharmony_ci	URNDIS_LOCK(sc);
271f9f848faSopenharmony_ci	error = urndis_ctrl_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
272f9f848faSopenharmony_ci	    &msg.hdr.set, sizeof(msg.hdr.set) + sizeof(msg.ibuf.filter));
273f9f848faSopenharmony_ci	URNDIS_UNLOCK(sc);
274f9f848faSopenharmony_ci	if (error != (int)RNDIS_STATUS_SUCCESS) {
275f9f848faSopenharmony_ci		device_printf(dev, "Unable to set data filters\n");
276f9f848faSopenharmony_ci		goto detach;
277f9f848faSopenharmony_ci	}
278f9f848faSopenharmony_ci
279f9f848faSopenharmony_ci	ue->ue_sc = sc;
280f9f848faSopenharmony_ci	ue->ue_dev = dev;
281f9f848faSopenharmony_ci	ue->ue_udev = uaa->device;
282f9f848faSopenharmony_ci	ue->ue_mtx = &sc->sc_mtx;
283f9f848faSopenharmony_ci	ue->ue_methods = &urndis_ue_methods;
284f9f848faSopenharmony_ci	error = uether_ifattach(ue);
285f9f848faSopenharmony_ci	if (error) {
286f9f848faSopenharmony_ci		device_printf(dev, "Could not attach interface\n");
287f9f848faSopenharmony_ci		goto detach;
288f9f848faSopenharmony_ci	}
289f9f848faSopenharmony_ci
290f9f848faSopenharmony_ci	error = (int)LOS_EventRead(&ue->ue_event, 0x01, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, 1000);
291f9f848faSopenharmony_ci	if (error == (int)LOS_ERRNO_EVENT_READ_TIMEOUT) {
292f9f848faSopenharmony_ci		device_printf(dev, "read sc_event fail , %x\n", error);
293f9f848faSopenharmony_ci		goto detach;
294f9f848faSopenharmony_ci	}
295f9f848faSopenharmony_ci
296f9f848faSopenharmony_ci	netif = &(ue->ue_drv_sc->ac_if);
297f9f848faSopenharmony_ci	if (!netif_is_up(netif)) {
298f9f848faSopenharmony_ci		(void)netifapi_netif_set_up(netif);
299f9f848faSopenharmony_ci	}
300f9f848faSopenharmony_ci
301f9f848faSopenharmony_ci	return (0);			/* success */
302f9f848faSopenharmony_ci
303f9f848faSopenharmony_cidetach:
304f9f848faSopenharmony_ci
305f9f848faSopenharmony_ci	(void)urndis_detach(dev);
306f9f848faSopenharmony_ci	return (ENXIO);			/* failure */
307f9f848faSopenharmony_ci}
308f9f848faSopenharmony_ci
309f9f848faSopenharmony_cistatic int
310f9f848faSopenharmony_ciurndis_detach(device_t dev)
311f9f848faSopenharmony_ci{
312f9f848faSopenharmony_ci	struct urndis_softc *sc = device_get_softc(dev);
313f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
314f9f848faSopenharmony_ci
315f9f848faSopenharmony_ci	/* stop all USB transfers first */
316f9f848faSopenharmony_ci	usbd_transfer_unsetup(sc->sc_xfer, URNDIS_N_TRANSFER);
317f9f848faSopenharmony_ci
318f9f848faSopenharmony_ci	uether_ifdetach(ue);
319f9f848faSopenharmony_ci
320f9f848faSopenharmony_ci	URNDIS_LOCK(sc);
321f9f848faSopenharmony_ci	(void)urndis_ctrl_halt(sc);
322f9f848faSopenharmony_ci	URNDIS_UNLOCK(sc);
323f9f848faSopenharmony_ci
324f9f848faSopenharmony_ci	mtx_destroy(&sc->sc_mtx);
325f9f848faSopenharmony_ci
326f9f848faSopenharmony_ci	return (0);
327f9f848faSopenharmony_ci}
328f9f848faSopenharmony_ci
329f9f848faSopenharmony_cistatic void
330f9f848faSopenharmony_ciurndis_start(struct usb_ether *ue)
331f9f848faSopenharmony_ci{
332f9f848faSopenharmony_ci	struct urndis_softc *sc = uether_getsc(ue);
333f9f848faSopenharmony_ci
334f9f848faSopenharmony_ci	/*
335f9f848faSopenharmony_ci	 * Start the USB transfers, if not already started:
336f9f848faSopenharmony_ci	 */
337f9f848faSopenharmony_ci	usbd_transfer_start(sc->sc_xfer[URNDIS_BULK_TX]);
338f9f848faSopenharmony_ci	usbd_transfer_start(sc->sc_xfer[URNDIS_BULK_RX]);
339f9f848faSopenharmony_ci}
340f9f848faSopenharmony_ci
341f9f848faSopenharmony_cistatic void
342f9f848faSopenharmony_ciurndis_init(struct usb_ether *ue)
343f9f848faSopenharmony_ci{
344f9f848faSopenharmony_ci	struct urndis_softc *sc = uether_getsc(ue);
345f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
346f9f848faSopenharmony_ci	struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)ifp->driver_context;
347f9f848faSopenharmony_ci
348f9f848faSopenharmony_ci	URNDIS_LOCK_ASSERT(sc, MA_OWNED);
349f9f848faSopenharmony_ci
350f9f848faSopenharmony_ci	drv_sc->state |= IFF_DRV_RUNNING;
351f9f848faSopenharmony_ci
352f9f848faSopenharmony_ci	/* stall data write direction, which depends on USB mode */
353f9f848faSopenharmony_ci	usbd_xfer_set_stall(sc->sc_xfer[URNDIS_BULK_TX]);
354f9f848faSopenharmony_ci
355f9f848faSopenharmony_ci	/* start data transfers */
356f9f848faSopenharmony_ci	urndis_start(ue);
357f9f848faSopenharmony_ci}
358f9f848faSopenharmony_ci
359f9f848faSopenharmony_cistatic void
360f9f848faSopenharmony_ciurndis_stop(struct usb_ether *ue)
361f9f848faSopenharmony_ci{
362f9f848faSopenharmony_ci	struct urndis_softc *sc = uether_getsc(ue);
363f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
364f9f848faSopenharmony_ci	struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)ifp->driver_context;
365f9f848faSopenharmony_ci
366f9f848faSopenharmony_ci	URNDIS_LOCK_ASSERT(sc, MA_OWNED);
367f9f848faSopenharmony_ci
368f9f848faSopenharmony_ci	drv_sc->state &= ~IFF_DRV_RUNNING;
369f9f848faSopenharmony_ci
370f9f848faSopenharmony_ci	/*
371f9f848faSopenharmony_ci	* stop all the transfers, if not already stopped:
372f9f848faSopenharmony_ci	*/
373f9f848faSopenharmony_ci	usbd_transfer_stop(sc->sc_xfer[URNDIS_BULK_RX]);
374f9f848faSopenharmony_ci	usbd_transfer_stop(sc->sc_xfer[URNDIS_BULK_TX]);
375f9f848faSopenharmony_ci}
376f9f848faSopenharmony_ci
377f9f848faSopenharmony_cistatic void
378f9f848faSopenharmony_ciurndis_setmulti(struct usb_ether *ue)
379f9f848faSopenharmony_ci{
380f9f848faSopenharmony_ci	/* no-op */
381f9f848faSopenharmony_ci}
382f9f848faSopenharmony_ci
383f9f848faSopenharmony_cistatic void
384f9f848faSopenharmony_ciurndis_setpromisc(struct usb_ether *ue)
385f9f848faSopenharmony_ci{
386f9f848faSopenharmony_ci	/* no-op */
387f9f848faSopenharmony_ci}
388f9f848faSopenharmony_ci
389f9f848faSopenharmony_cistatic int
390f9f848faSopenharmony_ciurndis_suspend(device_t dev)
391f9f848faSopenharmony_ci{
392f9f848faSopenharmony_ci	device_printf(dev, "Suspending\n");
393f9f848faSopenharmony_ci	return (0);
394f9f848faSopenharmony_ci}
395f9f848faSopenharmony_ci
396f9f848faSopenharmony_cistatic int
397f9f848faSopenharmony_ciurndis_resume(device_t dev)
398f9f848faSopenharmony_ci{
399f9f848faSopenharmony_ci	device_printf(dev, "Resuming\n");
400f9f848faSopenharmony_ci	return (0);
401f9f848faSopenharmony_ci}
402f9f848faSopenharmony_ci
403f9f848faSopenharmony_cistatic usb_error_t
404f9f848faSopenharmony_ciurndis_ctrl_msg(struct urndis_softc *sc, uint8_t rt, uint8_t r,
405f9f848faSopenharmony_ci    uint16_t index, uint16_t value, void *buf, uint16_t buflen)
406f9f848faSopenharmony_ci{
407f9f848faSopenharmony_ci	usb_device_request_t req;
408f9f848faSopenharmony_ci
409f9f848faSopenharmony_ci	req.bmRequestType = rt;
410f9f848faSopenharmony_ci	req.bRequest = r;
411f9f848faSopenharmony_ci	USETW(req.wValue, value);
412f9f848faSopenharmony_ci	USETW(req.wIndex, index);
413f9f848faSopenharmony_ci	USETW(req.wLength, buflen);
414f9f848faSopenharmony_ci
415f9f848faSopenharmony_ci	return (usbd_do_request_flags(sc->sc_ue.ue_udev,
416f9f848faSopenharmony_ci	    &sc->sc_mtx, &req, buf, (rt & UT_READ) ?
417f9f848faSopenharmony_ci	    USB_SHORT_XFER_OK : 0, NULL, 2000 /* ms */ ));
418f9f848faSopenharmony_ci}
419f9f848faSopenharmony_ci
420f9f848faSopenharmony_cistatic usb_error_t
421f9f848faSopenharmony_ciurndis_ctrl_send(struct urndis_softc *sc, void *buf, uint16_t len)
422f9f848faSopenharmony_ci{
423f9f848faSopenharmony_ci	usb_error_t err;
424f9f848faSopenharmony_ci
425f9f848faSopenharmony_ci	err = urndis_ctrl_msg(sc, UT_WRITE_CLASS_INTERFACE,
426f9f848faSopenharmony_ci	    UCDC_SEND_ENCAPSULATED_COMMAND, sc->sc_ifaceno_ctl, 0, buf, len);
427f9f848faSopenharmony_ci
428f9f848faSopenharmony_ci	DPRINTF("%s\n", usbd_errstr(err));
429f9f848faSopenharmony_ci
430f9f848faSopenharmony_ci	return (err);
431f9f848faSopenharmony_ci}
432f9f848faSopenharmony_ci
433f9f848faSopenharmony_cistatic struct urndis_comp_hdr *
434f9f848faSopenharmony_ciurndis_ctrl_recv(struct urndis_softc *sc)
435f9f848faSopenharmony_ci{
436f9f848faSopenharmony_ci	struct urndis_comp_hdr *hdr;
437f9f848faSopenharmony_ci	usb_error_t err;
438f9f848faSopenharmony_ci
439f9f848faSopenharmony_ci	err = urndis_ctrl_msg(sc, UT_READ_CLASS_INTERFACE,
440f9f848faSopenharmony_ci	    UCDC_GET_ENCAPSULATED_RESPONSE, sc->sc_ifaceno_ctl, 0,
441f9f848faSopenharmony_ci	    sc->sc_response_buf, RNDIS_RESPONSE_LEN);
442f9f848faSopenharmony_ci
443f9f848faSopenharmony_ci	if (err != USB_ERR_NORMAL_COMPLETION)
444f9f848faSopenharmony_ci		return (NULL);
445f9f848faSopenharmony_ci
446f9f848faSopenharmony_ci	hdr = (struct urndis_comp_hdr *)sc->sc_response_buf;
447f9f848faSopenharmony_ci
448f9f848faSopenharmony_ci	DPRINTF("type 0x%x len %u\n", le32toh(hdr->rm_type),
449f9f848faSopenharmony_ci	    le32toh(hdr->rm_len));
450f9f848faSopenharmony_ci
451f9f848faSopenharmony_ci	if (le32toh(hdr->rm_len) > RNDIS_RESPONSE_LEN) {
452f9f848faSopenharmony_ci		DPRINTF("ctrl message error: wrong size %u > %u\n",
453f9f848faSopenharmony_ci		    le32toh(hdr->rm_len), RNDIS_RESPONSE_LEN);
454f9f848faSopenharmony_ci		return (NULL);
455f9f848faSopenharmony_ci	}
456f9f848faSopenharmony_ci	return (hdr);
457f9f848faSopenharmony_ci}
458f9f848faSopenharmony_ci
459f9f848faSopenharmony_cistatic uint32_t
460f9f848faSopenharmony_ciurndis_ctrl_handle(struct urndis_softc *sc, struct urndis_comp_hdr *hdr,
461f9f848faSopenharmony_ci    const void **buf, uint16_t *bufsz)
462f9f848faSopenharmony_ci{
463f9f848faSopenharmony_ci	uint32_t rval;
464f9f848faSopenharmony_ci
465f9f848faSopenharmony_ci	DPRINTF("\n");
466f9f848faSopenharmony_ci
467f9f848faSopenharmony_ci	if (buf != NULL && bufsz != NULL) {
468f9f848faSopenharmony_ci		*buf = NULL;
469f9f848faSopenharmony_ci		*bufsz = 0;
470f9f848faSopenharmony_ci	}
471f9f848faSopenharmony_ci	switch (le32toh(hdr->rm_type)) {
472f9f848faSopenharmony_ci	case REMOTE_NDIS_INITIALIZE_CMPLT:
473f9f848faSopenharmony_ci		rval = urndis_ctrl_handle_init(sc, hdr);
474f9f848faSopenharmony_ci		break;
475f9f848faSopenharmony_ci
476f9f848faSopenharmony_ci	case REMOTE_NDIS_QUERY_CMPLT:
477f9f848faSopenharmony_ci		rval = urndis_ctrl_handle_query(sc, hdr, buf, bufsz);
478f9f848faSopenharmony_ci		break;
479f9f848faSopenharmony_ci
480f9f848faSopenharmony_ci	case REMOTE_NDIS_RESET_CMPLT:
481f9f848faSopenharmony_ci		rval = urndis_ctrl_handle_reset(sc, hdr);
482f9f848faSopenharmony_ci		break;
483f9f848faSopenharmony_ci
484f9f848faSopenharmony_ci	case REMOTE_NDIS_KEEPALIVE_CMPLT:
485f9f848faSopenharmony_ci		/* FALLTHROUGH */
486f9f848faSopenharmony_ci	case REMOTE_NDIS_SET_CMPLT:
487f9f848faSopenharmony_ci		rval = le32toh(hdr->rm_status);
488f9f848faSopenharmony_ci		break;
489f9f848faSopenharmony_ci
490f9f848faSopenharmony_ci	default:
491f9f848faSopenharmony_ci		device_printf(sc->sc_ue.ue_dev,
492f9f848faSopenharmony_ci		    "ctrl message error: unknown event 0x%x\n",
493f9f848faSopenharmony_ci		    le32toh(hdr->rm_type));
494f9f848faSopenharmony_ci		rval = RNDIS_STATUS_FAILURE;
495f9f848faSopenharmony_ci		break;
496f9f848faSopenharmony_ci	}
497f9f848faSopenharmony_ci	return (rval);
498f9f848faSopenharmony_ci}
499f9f848faSopenharmony_ci
500f9f848faSopenharmony_cistatic uint32_t
501f9f848faSopenharmony_ciurndis_ctrl_handle_init(struct urndis_softc *sc,
502f9f848faSopenharmony_ci	const struct urndis_comp_hdr *hdr)
503f9f848faSopenharmony_ci{
504f9f848faSopenharmony_ci	const struct urndis_init_comp *msg;
505f9f848faSopenharmony_ci
506f9f848faSopenharmony_ci	msg = (const struct urndis_init_comp *)hdr;
507f9f848faSopenharmony_ci
508f9f848faSopenharmony_ci	DPRINTF("len %u rid %u status 0x%x "
509f9f848faSopenharmony_ci	    "ver_major %u ver_minor %u devflags 0x%x medium 0x%x pktmaxcnt %u "
510f9f848faSopenharmony_ci	    "pktmaxsz %u align %u aflistoffset %u aflistsz %u\n",
511f9f848faSopenharmony_ci	    le32toh(msg->rm_len),
512f9f848faSopenharmony_ci	    le32toh(msg->rm_rid),
513f9f848faSopenharmony_ci	    le32toh(msg->rm_status),
514f9f848faSopenharmony_ci	    le32toh(msg->rm_ver_major),
515f9f848faSopenharmony_ci	    le32toh(msg->rm_ver_minor),
516f9f848faSopenharmony_ci	    le32toh(msg->rm_devflags),
517f9f848faSopenharmony_ci	    le32toh(msg->rm_medium),
518f9f848faSopenharmony_ci	    le32toh(msg->rm_pktmaxcnt),
519f9f848faSopenharmony_ci	    le32toh(msg->rm_pktmaxsz),
520f9f848faSopenharmony_ci	    le32toh(msg->rm_align),
521f9f848faSopenharmony_ci	    le32toh(msg->rm_aflistoffset),
522f9f848faSopenharmony_ci	    le32toh(msg->rm_aflistsz));
523f9f848faSopenharmony_ci
524f9f848faSopenharmony_ci	if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
525f9f848faSopenharmony_ci		DPRINTF("init failed 0x%x\n", le32toh(msg->rm_status));
526f9f848faSopenharmony_ci		return (le32toh(msg->rm_status));
527f9f848faSopenharmony_ci	}
528f9f848faSopenharmony_ci	if (le32toh(msg->rm_devflags) != RNDIS_DF_CONNECTIONLESS) {
529f9f848faSopenharmony_ci		DPRINTF("wrong device type (current type: 0x%x)\n",
530f9f848faSopenharmony_ci		    le32toh(msg->rm_devflags));
531f9f848faSopenharmony_ci		return (RNDIS_STATUS_FAILURE);
532f9f848faSopenharmony_ci	}
533f9f848faSopenharmony_ci	if (le32toh(msg->rm_medium) != RNDIS_MEDIUM_802_3) {
534f9f848faSopenharmony_ci		DPRINTF("medium not 802.3 (current medium: 0x%x)\n",
535f9f848faSopenharmony_ci		    le32toh(msg->rm_medium));
536f9f848faSopenharmony_ci		return (RNDIS_STATUS_FAILURE);
537f9f848faSopenharmony_ci	}
538f9f848faSopenharmony_ci	sc->sc_lim_pktsz = le32toh(msg->rm_pktmaxsz);
539f9f848faSopenharmony_ci
540f9f848faSopenharmony_ci	return (le32toh(msg->rm_status));
541f9f848faSopenharmony_ci}
542f9f848faSopenharmony_ci
543f9f848faSopenharmony_cistatic uint32_t
544f9f848faSopenharmony_ciurndis_ctrl_handle_query(struct urndis_softc *sc,
545f9f848faSopenharmony_ci    const struct urndis_comp_hdr *hdr, const void **buf, uint16_t *bufsz)
546f9f848faSopenharmony_ci{
547f9f848faSopenharmony_ci	const struct urndis_query_comp *msg;
548f9f848faSopenharmony_ci	uint64_t limit;
549f9f848faSopenharmony_ci        if (hdr == NULL || buf == NULL || bufsz == NULL) {
550f9f848faSopenharmony_ci            return RNDIS_STATUS_FAILURE;
551f9f848faSopenharmony_ci        }
552f9f848faSopenharmony_ci
553f9f848faSopenharmony_ci	msg = (const struct urndis_query_comp *)hdr;
554f9f848faSopenharmony_ci
555f9f848faSopenharmony_ci	DPRINTF("len %u rid %u status 0x%x "
556f9f848faSopenharmony_ci	    "buflen %u bufoff %u\n",
557f9f848faSopenharmony_ci	    le32toh(msg->rm_len),
558f9f848faSopenharmony_ci	    le32toh(msg->rm_rid),
559f9f848faSopenharmony_ci	    le32toh(msg->rm_status),
560f9f848faSopenharmony_ci	    le32toh(msg->rm_infobuflen),
561f9f848faSopenharmony_ci	    le32toh(msg->rm_infobufoffset));
562f9f848faSopenharmony_ci
563f9f848faSopenharmony_ci	*buf = NULL;
564f9f848faSopenharmony_ci	*bufsz = 0;
565f9f848faSopenharmony_ci	if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
566f9f848faSopenharmony_ci		DPRINTF("query failed 0x%x\n", le32toh(msg->rm_status));
567f9f848faSopenharmony_ci		return (le32toh(msg->rm_status));
568f9f848faSopenharmony_ci	}
569f9f848faSopenharmony_ci	limit = le32toh(msg->rm_infobuflen);
570f9f848faSopenharmony_ci	limit += le32toh(msg->rm_infobufoffset);
571f9f848faSopenharmony_ci	limit += RNDIS_HEADER_OFFSET;
572f9f848faSopenharmony_ci
573f9f848faSopenharmony_ci	if (limit > (uint64_t)le32toh(msg->rm_len)) {
574f9f848faSopenharmony_ci		DPRINTF("ctrl message error: invalid query info "
575f9f848faSopenharmony_ci		    "len/offset/end_position(%u/%u/%u) -> "
576f9f848faSopenharmony_ci		    "go out of buffer limit %u\n",
577f9f848faSopenharmony_ci		    le32toh(msg->rm_infobuflen),
578f9f848faSopenharmony_ci		    le32toh(msg->rm_infobufoffset),
579f9f848faSopenharmony_ci		    le32toh(msg->rm_infobuflen) +
580f9f848faSopenharmony_ci		    le32toh(msg->rm_infobufoffset) + RNDIS_HEADER_OFFSET,
581f9f848faSopenharmony_ci		    le32toh(msg->rm_len));
582f9f848faSopenharmony_ci		return (RNDIS_STATUS_FAILURE);
583f9f848faSopenharmony_ci	}
584f9f848faSopenharmony_ci	*buf = ((const uint8_t *)msg) + RNDIS_HEADER_OFFSET +
585f9f848faSopenharmony_ci	    le32toh(msg->rm_infobufoffset);
586f9f848faSopenharmony_ci	*bufsz = le32toh(msg->rm_infobuflen);
587f9f848faSopenharmony_ci
588f9f848faSopenharmony_ci	return (le32toh(msg->rm_status));
589f9f848faSopenharmony_ci}
590f9f848faSopenharmony_ci
591f9f848faSopenharmony_cistatic uint32_t
592f9f848faSopenharmony_ciurndis_ctrl_handle_reset(struct urndis_softc *sc,
593f9f848faSopenharmony_ci    const struct urndis_comp_hdr *hdr)
594f9f848faSopenharmony_ci{
595f9f848faSopenharmony_ci	const struct urndis_reset_comp *msg;
596f9f848faSopenharmony_ci	uint32_t rval;
597f9f848faSopenharmony_ci
598f9f848faSopenharmony_ci	msg = (const struct urndis_reset_comp *)hdr;
599f9f848faSopenharmony_ci
600f9f848faSopenharmony_ci	rval = le32toh(msg->rm_status);
601f9f848faSopenharmony_ci
602f9f848faSopenharmony_ci	DPRINTF("len %u status 0x%x "
603f9f848faSopenharmony_ci	    "adrreset %u\n",
604f9f848faSopenharmony_ci	    le32toh(msg->rm_len),
605f9f848faSopenharmony_ci	    rval,
606f9f848faSopenharmony_ci	    le32toh(msg->rm_adrreset));
607f9f848faSopenharmony_ci
608f9f848faSopenharmony_ci	if (rval != RNDIS_STATUS_SUCCESS) {
609f9f848faSopenharmony_ci		DPRINTF("reset failed 0x%x\n", rval);
610f9f848faSopenharmony_ci		return (rval);
611f9f848faSopenharmony_ci	}
612f9f848faSopenharmony_ci	if (msg->rm_adrreset != 0) {
613f9f848faSopenharmony_ci		struct {
614f9f848faSopenharmony_ci			struct urndis_set_req hdr;
615f9f848faSopenharmony_ci			uint32_t filter;
616f9f848faSopenharmony_ci		} msg_filter;
617f9f848faSopenharmony_ci
618f9f848faSopenharmony_ci		msg_filter.filter = htole32(sc->sc_filter);
619f9f848faSopenharmony_ci
620f9f848faSopenharmony_ci		rval = urndis_ctrl_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
621f9f848faSopenharmony_ci		    &msg_filter.hdr, sizeof(msg_filter));
622f9f848faSopenharmony_ci
623f9f848faSopenharmony_ci		if (rval != RNDIS_STATUS_SUCCESS) {
624f9f848faSopenharmony_ci			DPRINTF("unable to reset data filters\n");
625f9f848faSopenharmony_ci			return (rval);
626f9f848faSopenharmony_ci		}
627f9f848faSopenharmony_ci	}
628f9f848faSopenharmony_ci	return (rval);
629f9f848faSopenharmony_ci}
630f9f848faSopenharmony_ci
631f9f848faSopenharmony_cistatic uint32_t
632f9f848faSopenharmony_ciurndis_ctrl_init(struct urndis_softc *sc)
633f9f848faSopenharmony_ci{
634f9f848faSopenharmony_ci	struct urndis_init_req msg;
635f9f848faSopenharmony_ci	struct urndis_comp_hdr *hdr;
636f9f848faSopenharmony_ci	uint32_t rval;
637f9f848faSopenharmony_ci
638f9f848faSopenharmony_ci	msg.rm_type = htole32(REMOTE_NDIS_INITIALIZE_MSG);
639f9f848faSopenharmony_ci	msg.rm_len = htole32(sizeof(msg));
640f9f848faSopenharmony_ci	msg.rm_rid = 0;
641f9f848faSopenharmony_ci	msg.rm_ver_major = htole32(1);
642f9f848faSopenharmony_ci	msg.rm_ver_minor = htole32(1);
643f9f848faSopenharmony_ci	msg.rm_max_xfersz = htole32(RNDIS_RX_MAXLEN);
644f9f848faSopenharmony_ci
645f9f848faSopenharmony_ci	DPRINTF("type %u len %u rid %u ver_major %u "
646f9f848faSopenharmony_ci	    "ver_minor %u max_xfersz %u\n",
647f9f848faSopenharmony_ci	    le32toh(msg.rm_type),
648f9f848faSopenharmony_ci	    le32toh(msg.rm_len),
649f9f848faSopenharmony_ci	    le32toh(msg.rm_rid),
650f9f848faSopenharmony_ci	    le32toh(msg.rm_ver_major),
651f9f848faSopenharmony_ci	    le32toh(msg.rm_ver_minor),
652f9f848faSopenharmony_ci	    le32toh(msg.rm_max_xfersz));
653f9f848faSopenharmony_ci
654f9f848faSopenharmony_ci	rval = urndis_ctrl_send(sc, &msg, sizeof(msg));
655f9f848faSopenharmony_ci
656f9f848faSopenharmony_ci	if (rval != RNDIS_STATUS_SUCCESS) {
657f9f848faSopenharmony_ci		DPRINTF("init failed\n");
658f9f848faSopenharmony_ci		return (rval);
659f9f848faSopenharmony_ci	}
660f9f848faSopenharmony_ci	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
661f9f848faSopenharmony_ci		DPRINTF("unable to get init response\n");
662f9f848faSopenharmony_ci		return (RNDIS_STATUS_FAILURE);
663f9f848faSopenharmony_ci	}
664f9f848faSopenharmony_ci	rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
665f9f848faSopenharmony_ci
666f9f848faSopenharmony_ci	return (rval);
667f9f848faSopenharmony_ci}
668f9f848faSopenharmony_ci
669f9f848faSopenharmony_cistatic uint32_t
670f9f848faSopenharmony_ciurndis_ctrl_halt(struct urndis_softc *sc)
671f9f848faSopenharmony_ci{
672f9f848faSopenharmony_ci	struct urndis_halt_req msg;
673f9f848faSopenharmony_ci	uint32_t rval;
674f9f848faSopenharmony_ci
675f9f848faSopenharmony_ci	msg.rm_type = htole32(REMOTE_NDIS_HALT_MSG);
676f9f848faSopenharmony_ci	msg.rm_len = htole32(sizeof(msg));
677f9f848faSopenharmony_ci	msg.rm_rid = 0;
678f9f848faSopenharmony_ci
679f9f848faSopenharmony_ci	DPRINTF("type %u len %u rid %u\n",
680f9f848faSopenharmony_ci	    le32toh(msg.rm_type),
681f9f848faSopenharmony_ci	    le32toh(msg.rm_len),
682f9f848faSopenharmony_ci	    le32toh(msg.rm_rid));
683f9f848faSopenharmony_ci
684f9f848faSopenharmony_ci	rval = urndis_ctrl_send(sc, &msg, sizeof(msg));
685f9f848faSopenharmony_ci
686f9f848faSopenharmony_ci	if (rval != RNDIS_STATUS_SUCCESS)
687f9f848faSopenharmony_ci		DPRINTF("halt failed\n");
688f9f848faSopenharmony_ci
689f9f848faSopenharmony_ci	return (rval);
690f9f848faSopenharmony_ci}
691f9f848faSopenharmony_ci
692f9f848faSopenharmony_ci/*
693f9f848faSopenharmony_ci * NB: Querying a device has the requirment of using an input buffer the size
694f9f848faSopenharmony_ci *	 of the expected reply or larger, except for variably sized replies.
695f9f848faSopenharmony_ci */
696f9f848faSopenharmony_cistatic uint32_t
697f9f848faSopenharmony_ciurndis_ctrl_query(struct urndis_softc *sc, uint32_t oid,
698f9f848faSopenharmony_ci    struct urndis_query_req *msg, uint16_t len, const void **rbuf,
699f9f848faSopenharmony_ci    uint16_t *rbufsz)
700f9f848faSopenharmony_ci{
701f9f848faSopenharmony_ci	struct urndis_comp_hdr *hdr;
702f9f848faSopenharmony_ci	uint32_t datalen, rval;
703f9f848faSopenharmony_ci
704f9f848faSopenharmony_ci	msg->rm_type = htole32(REMOTE_NDIS_QUERY_MSG);
705f9f848faSopenharmony_ci	msg->rm_len = htole32(len);
706f9f848faSopenharmony_ci	msg->rm_rid = 0;		/* XXX */
707f9f848faSopenharmony_ci	msg->rm_oid = htole32(oid);
708f9f848faSopenharmony_ci	datalen = len - sizeof(*msg);
709f9f848faSopenharmony_ci	msg->rm_infobuflen = htole32(datalen);
710f9f848faSopenharmony_ci	if (datalen != 0) {
711f9f848faSopenharmony_ci		msg->rm_infobufoffset = htole32(sizeof(*msg) -
712f9f848faSopenharmony_ci		    RNDIS_HEADER_OFFSET);
713f9f848faSopenharmony_ci	} else {
714f9f848faSopenharmony_ci		msg->rm_infobufoffset = 0;
715f9f848faSopenharmony_ci	}
716f9f848faSopenharmony_ci	msg->rm_devicevchdl = 0;
717f9f848faSopenharmony_ci
718f9f848faSopenharmony_ci	DPRINTF("type %u len %u rid %u oid 0x%x "
719f9f848faSopenharmony_ci	    "infobuflen %u infobufoffset %u devicevchdl %u\n",
720f9f848faSopenharmony_ci	    le32toh(msg->rm_type),
721f9f848faSopenharmony_ci	    le32toh(msg->rm_len),
722f9f848faSopenharmony_ci	    le32toh(msg->rm_rid),
723f9f848faSopenharmony_ci	    le32toh(msg->rm_oid),
724f9f848faSopenharmony_ci	    le32toh(msg->rm_infobuflen),
725f9f848faSopenharmony_ci	    le32toh(msg->rm_infobufoffset),
726f9f848faSopenharmony_ci	    le32toh(msg->rm_devicevchdl));
727f9f848faSopenharmony_ci
728f9f848faSopenharmony_ci	rval = urndis_ctrl_send(sc, msg, len);
729f9f848faSopenharmony_ci
730f9f848faSopenharmony_ci	if (rval != RNDIS_STATUS_SUCCESS) {
731f9f848faSopenharmony_ci		DPRINTF("query failed\n");
732f9f848faSopenharmony_ci		return (rval);
733f9f848faSopenharmony_ci	}
734f9f848faSopenharmony_ci	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
735f9f848faSopenharmony_ci		DPRINTF("unable to get query response\n");
736f9f848faSopenharmony_ci		return (RNDIS_STATUS_FAILURE);
737f9f848faSopenharmony_ci	}
738f9f848faSopenharmony_ci	rval = urndis_ctrl_handle(sc, hdr, rbuf, rbufsz);
739f9f848faSopenharmony_ci
740f9f848faSopenharmony_ci	return (rval);
741f9f848faSopenharmony_ci}
742f9f848faSopenharmony_ci
743f9f848faSopenharmony_cistatic uint32_t
744f9f848faSopenharmony_ciurndis_ctrl_set(struct urndis_softc *sc, uint32_t oid,
745f9f848faSopenharmony_ci    struct urndis_set_req *msg, uint16_t len)
746f9f848faSopenharmony_ci{
747f9f848faSopenharmony_ci	struct urndis_comp_hdr *hdr;
748f9f848faSopenharmony_ci	uint32_t datalen, rval;
749f9f848faSopenharmony_ci
750f9f848faSopenharmony_ci	msg->rm_type = htole32(REMOTE_NDIS_SET_MSG);
751f9f848faSopenharmony_ci	msg->rm_len = htole32(len);
752f9f848faSopenharmony_ci	msg->rm_rid = 0;		/* XXX */
753f9f848faSopenharmony_ci	msg->rm_oid = htole32(oid);
754f9f848faSopenharmony_ci	datalen = len - sizeof(*msg);
755f9f848faSopenharmony_ci	msg->rm_infobuflen = htole32(datalen);
756f9f848faSopenharmony_ci	if (datalen != 0) {
757f9f848faSopenharmony_ci		msg->rm_infobufoffset = htole32(sizeof(*msg) -
758f9f848faSopenharmony_ci		    RNDIS_HEADER_OFFSET);
759f9f848faSopenharmony_ci	} else {
760f9f848faSopenharmony_ci		msg->rm_infobufoffset = 0;
761f9f848faSopenharmony_ci	}
762f9f848faSopenharmony_ci	msg->rm_devicevchdl = 0;
763f9f848faSopenharmony_ci
764f9f848faSopenharmony_ci	DPRINTF("type %u len %u rid %u oid 0x%x "
765f9f848faSopenharmony_ci	    "infobuflen %u infobufoffset %u devicevchdl %u\n",
766f9f848faSopenharmony_ci	    le32toh(msg->rm_type),
767f9f848faSopenharmony_ci	    le32toh(msg->rm_len),
768f9f848faSopenharmony_ci	    le32toh(msg->rm_rid),
769f9f848faSopenharmony_ci	    le32toh(msg->rm_oid),
770f9f848faSopenharmony_ci	    le32toh(msg->rm_infobuflen),
771f9f848faSopenharmony_ci	    le32toh(msg->rm_infobufoffset),
772f9f848faSopenharmony_ci	    le32toh(msg->rm_devicevchdl));
773f9f848faSopenharmony_ci
774f9f848faSopenharmony_ci	rval = urndis_ctrl_send(sc, msg, len);
775f9f848faSopenharmony_ci
776f9f848faSopenharmony_ci	if (rval != RNDIS_STATUS_SUCCESS) {
777f9f848faSopenharmony_ci		DPRINTF("set failed\n");
778f9f848faSopenharmony_ci		return (rval);
779f9f848faSopenharmony_ci	}
780f9f848faSopenharmony_ci	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
781f9f848faSopenharmony_ci		DPRINTF("unable to get set response\n");
782f9f848faSopenharmony_ci		return (RNDIS_STATUS_FAILURE);
783f9f848faSopenharmony_ci	}
784f9f848faSopenharmony_ci	rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
785f9f848faSopenharmony_ci	if (rval != RNDIS_STATUS_SUCCESS)
786f9f848faSopenharmony_ci		DPRINTF("set failed 0x%x\n", rval);
787f9f848faSopenharmony_ci
788f9f848faSopenharmony_ci	return (rval);
789f9f848faSopenharmony_ci}
790f9f848faSopenharmony_ci
791f9f848faSopenharmony_ci#define		OFFSET_OF(type, field) \
792f9f848faSopenharmony_ci	((size_t)(uintptr_t)((const volatile void *)&((type *)0)->field))
793f9f848faSopenharmony_ci
794f9f848faSopenharmony_cistatic int urndis_bulk_read(struct usb_xfer *xfer, struct urndis_packet_msg *msg, int offset)
795f9f848faSopenharmony_ci{
796f9f848faSopenharmony_ci	struct urndis_softc *sc = usbd_xfer_softc(xfer);
797f9f848faSopenharmony_ci	struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0);
798f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
799f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
800f9f848faSopenharmony_ci	struct pbuf *m;
801f9f848faSopenharmony_ci
802f9f848faSopenharmony_ci	m = pbuf_alloc(PBUF_RAW, msg->rm_datalen + ETH_PAD_SIZE, PBUF_RAM);
803f9f848faSopenharmony_ci	if (m == NULL){
804f9f848faSopenharmony_ci		DPRINTF("pbuf_alloc failed\n");
805f9f848faSopenharmony_ci		return (-1);
806f9f848faSopenharmony_ci	}
807f9f848faSopenharmony_ci
808f9f848faSopenharmony_ci	#if ETH_PAD_SIZE
809f9f848faSopenharmony_ci	/* drop the padding word */
810f9f848faSopenharmony_ci	if (pbuf_header(m, -ETH_PAD_SIZE)) {
811f9f848faSopenharmony_ci		PRINTK("[URNDIS_ERROR]urndis_rxeof : pbuf_header drop failed\n");
812f9f848faSopenharmony_ci		(void) pbuf_free(m);
813f9f848faSopenharmony_ci		return (-1);
814f9f848faSopenharmony_ci	}
815f9f848faSopenharmony_ci	#endif
816f9f848faSopenharmony_ci
817f9f848faSopenharmony_ci	usbd_copy_out(pc, offset + msg->rm_dataoffset +
818f9f848faSopenharmony_ci				  OFFSET_OF(struct urndis_packet_msg, rm_dataoffset), m->payload, msg->rm_datalen);
819f9f848faSopenharmony_ci
820f9f848faSopenharmony_ci	#if ETH_PAD_SIZE
821f9f848faSopenharmony_ci	/* reclaim the padding word */
822f9f848faSopenharmony_ci	if (pbuf_header(m, ETH_PAD_SIZE)) {
823f9f848faSopenharmony_ci		PRINTK("[URNDIS_ERROR]urndis_rxeof : pbuf_header drop failed\n");
824f9f848faSopenharmony_ci		(void) pbuf_free(m);
825f9f848faSopenharmony_ci		return (-1);
826f9f848faSopenharmony_ci	}
827f9f848faSopenharmony_ci	#endif
828f9f848faSopenharmony_ci
829f9f848faSopenharmony_ci	/* enqueue */
830f9f848faSopenharmony_ci	driverif_input(&ifp->ac_if, m);
831f9f848faSopenharmony_ci
832f9f848faSopenharmony_ci	return (0);
833f9f848faSopenharmony_ci}
834f9f848faSopenharmony_ci
835f9f848faSopenharmony_cistatic void
836f9f848faSopenharmony_ciurndis_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
837f9f848faSopenharmony_ci{
838f9f848faSopenharmony_ci	struct urndis_softc *sc = usbd_xfer_softc(xfer);
839f9f848faSopenharmony_ci	struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0);
840f9f848faSopenharmony_ci	struct urndis_packet_msg msg;
841f9f848faSopenharmony_ci	int actlen;
842f9f848faSopenharmony_ci	int aframes;
843f9f848faSopenharmony_ci	int offset;
844f9f848faSopenharmony_ci
845f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer)) {
846f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
847f9f848faSopenharmony_ci		usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
848f9f848faSopenharmony_ci
849f9f848faSopenharmony_ci		DPRINTFN(1, "received %u bytes in %u frames\n", actlen, aframes);
850f9f848faSopenharmony_ci
851f9f848faSopenharmony_ci		for (offset = 0; actlen >= (int)sizeof(msg);) {
852f9f848faSopenharmony_ci			/* copy out header */
853f9f848faSopenharmony_ci			usbd_copy_out(pc, offset, &msg, sizeof(msg));
854f9f848faSopenharmony_ci
855f9f848faSopenharmony_ci			if (le32toh(0x1234567U) != 0x1234567U) {
856f9f848faSopenharmony_ci				/* swap endianness */
857f9f848faSopenharmony_ci				msg.rm_type = le32toh(msg.rm_type);
858f9f848faSopenharmony_ci				msg.rm_len = le32toh(msg.rm_len);
859f9f848faSopenharmony_ci				msg.rm_dataoffset = le32toh(msg.rm_dataoffset);
860f9f848faSopenharmony_ci				msg.rm_datalen = le32toh(msg.rm_datalen);
861f9f848faSopenharmony_ci				msg.rm_oobdataoffset = le32toh(msg.rm_oobdataoffset);
862f9f848faSopenharmony_ci				msg.rm_oobdatalen = le32toh(msg.rm_oobdatalen);
863f9f848faSopenharmony_ci				msg.rm_oobdataelements = le32toh(msg.rm_oobdataelements);
864f9f848faSopenharmony_ci				msg.rm_pktinfooffset = le32toh(msg.rm_pktinfooffset);
865f9f848faSopenharmony_ci				msg.rm_pktinfolen = le32toh(msg.rm_pktinfolen);
866f9f848faSopenharmony_ci				msg.rm_vchandle = le32toh(msg.rm_vchandle);
867f9f848faSopenharmony_ci				msg.rm_reserved = le32toh(msg.rm_reserved);
868f9f848faSopenharmony_ci			}
869f9f848faSopenharmony_ci
870f9f848faSopenharmony_ci			DPRINTF("len %u data(off:%u len:%u) "
871f9f848faSopenharmony_ci			    "oobdata(off:%u len:%u nb:%u) perpacket(off:%u len:%u)\n",
872f9f848faSopenharmony_ci			    msg.rm_len, msg.rm_dataoffset, msg.rm_datalen,
873f9f848faSopenharmony_ci			    msg.rm_oobdataoffset, msg.rm_oobdatalen,
874f9f848faSopenharmony_ci			    msg.rm_oobdataelements, msg.rm_pktinfooffset,
875f9f848faSopenharmony_ci			    msg.rm_pktinfooffset);
876f9f848faSopenharmony_ci
877f9f848faSopenharmony_ci			/* sanity check the RNDIS header */
878f9f848faSopenharmony_ci			if (msg.rm_type != REMOTE_NDIS_PACKET_MSG) {
879f9f848faSopenharmony_ci				DPRINTF("invalid type 0x%x != 0x%x\n",
880f9f848faSopenharmony_ci				    msg.rm_type, REMOTE_NDIS_PACKET_MSG);
881f9f848faSopenharmony_ci				goto tr_setup;
882f9f848faSopenharmony_ci			} else if (msg.rm_len < (uint32_t)sizeof(msg)) {
883f9f848faSopenharmony_ci				DPRINTF("invalid msg len %u < %u\n",
884f9f848faSopenharmony_ci				    msg.rm_len, (unsigned)sizeof(msg));
885f9f848faSopenharmony_ci				goto tr_setup;
886f9f848faSopenharmony_ci			} else if (msg.rm_len > (uint32_t)actlen) {
887f9f848faSopenharmony_ci				DPRINTF("invalid msg len %u > buffer "
888f9f848faSopenharmony_ci				    "len %u\n", msg.rm_len, actlen);
889f9f848faSopenharmony_ci				goto tr_setup;
890f9f848faSopenharmony_ci			} else if (msg.rm_dataoffset >= (uint32_t)actlen) {
891f9f848faSopenharmony_ci				DPRINTF("invalid msg dataoffset %u > buffer "
892f9f848faSopenharmony_ci				    "dataoffset %u\n", msg.rm_dataoffset, actlen);
893f9f848faSopenharmony_ci				goto tr_setup;
894f9f848faSopenharmony_ci			} else if (msg.rm_datalen > (uint32_t)actlen) {
895f9f848faSopenharmony_ci				DPRINTF("invalid msg datalen %u > buffer "
896f9f848faSopenharmony_ci				    "datalen %u\n", msg.rm_datalen, actlen);
897f9f848faSopenharmony_ci				goto tr_setup;
898f9f848faSopenharmony_ci			} else if (msg.rm_datalen < (uint32_t)sizeof(struct ether_header)) {
899f9f848faSopenharmony_ci				DPRINTF("invalid ethernet size "
900f9f848faSopenharmony_ci				    "%u < %u\n", msg.rm_datalen, (unsigned)sizeof(struct ether_header));
901f9f848faSopenharmony_ci				goto tr_setup;
902f9f848faSopenharmony_ci			} else if (msg.rm_datalen > (uint32_t)(MCLBYTES - ETHER_ALIGN)) {
903f9f848faSopenharmony_ci				DPRINTF("invalid ethernet size "
904f9f848faSopenharmony_ci				    "%u > %u\n",
905f9f848faSopenharmony_ci				    msg.rm_datalen, (unsigned)MCLBYTES);
906f9f848faSopenharmony_ci				goto tr_setup;
907f9f848faSopenharmony_ci			} else {
908f9f848faSopenharmony_ci				if (0 != urndis_bulk_read(xfer, &msg, offset)) {
909f9f848faSopenharmony_ci					return;
910f9f848faSopenharmony_ci				}
911f9f848faSopenharmony_ci			}
912f9f848faSopenharmony_ci
913f9f848faSopenharmony_ci			offset += msg.rm_len;
914f9f848faSopenharmony_ci			actlen -= msg.rm_len;
915f9f848faSopenharmony_ci		}
916f9f848faSopenharmony_ci		/* FALLTHROUGH */
917f9f848faSopenharmony_ci
918f9f848faSopenharmony_ci	case USB_ST_SETUP:
919f9f848faSopenharmony_citr_setup:
920f9f848faSopenharmony_ci
921f9f848faSopenharmony_ci		usbd_xfer_set_frame_len(xfer, 0, RNDIS_RX_MAXLEN);
922f9f848faSopenharmony_ci		usbd_xfer_set_frames(xfer, 1);
923f9f848faSopenharmony_ci		usbd_transfer_submit(xfer);
924f9f848faSopenharmony_ci		uether_rxflush(&sc->sc_ue);	/* must be last */
925f9f848faSopenharmony_ci		break;
926f9f848faSopenharmony_ci
927f9f848faSopenharmony_ci	default:			/* Error */
928f9f848faSopenharmony_ci		DPRINTFN(1, "error = %s\n", usbd_errstr(error));
929f9f848faSopenharmony_ci
930f9f848faSopenharmony_ci		if (error != USB_ERR_CANCELLED) {
931f9f848faSopenharmony_ci			/* try to clear stall first */
932f9f848faSopenharmony_ci			usbd_xfer_set_stall(xfer);
933f9f848faSopenharmony_ci			usbd_xfer_set_frames(xfer, 0);
934f9f848faSopenharmony_ci			usbd_transfer_submit(xfer);
935f9f848faSopenharmony_ci		}
936f9f848faSopenharmony_ci		break;
937f9f848faSopenharmony_ci	}
938f9f848faSopenharmony_ci}
939f9f848faSopenharmony_ci
940f9f848faSopenharmony_cistatic void
941f9f848faSopenharmony_ciurndis_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
942f9f848faSopenharmony_ci{
943f9f848faSopenharmony_ci	struct urndis_packet_msg msg;
944f9f848faSopenharmony_ci	struct urndis_softc *sc = usbd_xfer_softc(xfer);
945f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
946f9f848faSopenharmony_ci	struct pbuf *m;
947f9f848faSopenharmony_ci	unsigned x;
948f9f848faSopenharmony_ci	int actlen;
949f9f848faSopenharmony_ci	int aframes;
950f9f848faSopenharmony_ci
951f9f848faSopenharmony_ci	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
952f9f848faSopenharmony_ci
953f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
954f9f848faSopenharmony_ci
955f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer)) {
956f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
957f9f848faSopenharmony_ci	DPRINTFN(11, "%u bytes in %u frames\n", actlen, aframes);
958f9f848faSopenharmony_ci
959f9f848faSopenharmony_ci	/* FALLTHROUGH */
960f9f848faSopenharmony_ci	case USB_ST_SETUP:
961f9f848faSopenharmony_citr_setup:
962f9f848faSopenharmony_ci		(void)memset_s(&msg, sizeof(msg), 0, sizeof(msg));
963f9f848faSopenharmony_ci
964f9f848faSopenharmony_ci		for (x = 0; x != RNDIS_TX_FRAMES_MAX; x++) {
965f9f848faSopenharmony_ci			struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, x);
966f9f848faSopenharmony_ci
967f9f848faSopenharmony_ci			usbd_xfer_set_frame_offset(xfer, x * RNDIS_TX_MAXLEN, x);
968f9f848faSopenharmony_ci
969f9f848faSopenharmony_cinext_pkt:
970f9f848faSopenharmony_ci			UE_LOCK(ue);
971f9f848faSopenharmony_ci			IF_DEQUEUE(&(ue->ue_txq), m);
972f9f848faSopenharmony_ci			UE_UNLOCK(ue);
973f9f848faSopenharmony_ci
974f9f848faSopenharmony_ci			if (m == NULL)
975f9f848faSopenharmony_ci				break;
976f9f848faSopenharmony_ci
977f9f848faSopenharmony_ci			if ((m->len + sizeof(msg)) > RNDIS_TX_MAXLEN) {
978f9f848faSopenharmony_ci				DPRINTF("Too big packet\n");
979f9f848faSopenharmony_ci
980f9f848faSopenharmony_ci				/* Free buffer */
981f9f848faSopenharmony_ci				uether_freebuf(m);
982f9f848faSopenharmony_ci				goto next_pkt;
983f9f848faSopenharmony_ci			}
984f9f848faSopenharmony_ci			msg.rm_type = htole32(REMOTE_NDIS_PACKET_MSG);
985f9f848faSopenharmony_ci			msg.rm_len = htole32(sizeof(msg) + m->len);
986f9f848faSopenharmony_ci
987f9f848faSopenharmony_ci			msg.rm_dataoffset = htole32(RNDIS_DATA_OFFSET);
988f9f848faSopenharmony_ci			msg.rm_datalen = htole32(m->len);
989f9f848faSopenharmony_ci
990f9f848faSopenharmony_ci			/* copy in all data */
991f9f848faSopenharmony_ci			usbd_copy_in(pc, 0, &msg, sizeof(msg));
992f9f848faSopenharmony_ci			usbd_copy_in(pc, sizeof(msg), m->payload, m->len);
993f9f848faSopenharmony_ci			usbd_xfer_set_frame_len(xfer, x, sizeof(msg) + m->len);
994f9f848faSopenharmony_ci
995f9f848faSopenharmony_ci			/* Free buffer */
996f9f848faSopenharmony_ci			uether_freebuf(m);
997f9f848faSopenharmony_ci		}
998f9f848faSopenharmony_ci		if (x != 0) {
999f9f848faSopenharmony_ci			usbd_xfer_set_frames(xfer, x);
1000f9f848faSopenharmony_ci			usbd_transfer_submit(xfer);
1001f9f848faSopenharmony_ci		}
1002f9f848faSopenharmony_ci		break;
1003f9f848faSopenharmony_ci
1004f9f848faSopenharmony_ci	default:			/* Error */
1005f9f848faSopenharmony_ci		DPRINTFN(11, "transfer error, %s\n", usbd_errstr(error));
1006f9f848faSopenharmony_ci
1007f9f848faSopenharmony_ci		if (error != USB_ERR_CANCELLED) {
1008f9f848faSopenharmony_ci			/* try to clear stall first */
1009f9f848faSopenharmony_ci			usbd_xfer_set_stall(xfer);
1010f9f848faSopenharmony_ci			goto tr_setup;
1011f9f848faSopenharmony_ci		}
1012f9f848faSopenharmony_ci		break;
1013f9f848faSopenharmony_ci	}
1014f9f848faSopenharmony_ci}
1015f9f848faSopenharmony_ci
1016f9f848faSopenharmony_cistatic void
1017f9f848faSopenharmony_ciurndis_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
1018f9f848faSopenharmony_ci{
1019f9f848faSopenharmony_ci	int actlen;
1020f9f848faSopenharmony_ci
1021f9f848faSopenharmony_ci	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1022f9f848faSopenharmony_ci
1023f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer)) {
1024f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
1025f9f848faSopenharmony_ci
1026f9f848faSopenharmony_ci		DPRINTF("Received %d bytes\n", actlen);
1027f9f848faSopenharmony_ci
1028f9f848faSopenharmony_ci		/* TODO: decode some indications */
1029f9f848faSopenharmony_ci
1030f9f848faSopenharmony_ci		/* FALLTHROUGH */
1031f9f848faSopenharmony_ci	case USB_ST_SETUP:
1032f9f848faSopenharmony_citr_setup:
1033f9f848faSopenharmony_ci		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
1034f9f848faSopenharmony_ci		usbd_transfer_submit(xfer);
1035f9f848faSopenharmony_ci		break;
1036f9f848faSopenharmony_ci
1037f9f848faSopenharmony_ci	default:			/* Error */
1038f9f848faSopenharmony_ci		if (error != USB_ERR_CANCELLED) {
1039f9f848faSopenharmony_ci			/* start clear stall */
1040f9f848faSopenharmony_ci			usbd_xfer_set_stall(xfer);
1041f9f848faSopenharmony_ci			goto tr_setup;
1042f9f848faSopenharmony_ci		}
1043f9f848faSopenharmony_ci		break;
1044f9f848faSopenharmony_ci	}
1045f9f848faSopenharmony_ci}
1046f9f848faSopenharmony_ci
1047f9f848faSopenharmony_ci#undef USB_DEBUG_VAR
1048