1f9f848faSopenharmony_ci/*	$NetBSD: if_cdce.c,v 1.4 2004/10/24 12:50:54 augustss Exp $ */
2f9f848faSopenharmony_ci
3f9f848faSopenharmony_ci/*-
4f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-4-Clause
5f9f848faSopenharmony_ci *
6f9f848faSopenharmony_ci * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com>
7f9f848faSopenharmony_ci * Copyright (c) 2003-2005 Craig Boston
8f9f848faSopenharmony_ci * Copyright (c) 2004 Daniel Hartmeier
9f9f848faSopenharmony_ci * Copyright (c) 2009 Hans Petter Selasky
10f9f848faSopenharmony_ci * All rights reserved.
11f9f848faSopenharmony_ci *
12f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without
13f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions
14f9f848faSopenharmony_ci * are met:
15f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright
16f9f848faSopenharmony_ci *    notice, this list of conditions and the following disclaimer.
17f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
18f9f848faSopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
19f9f848faSopenharmony_ci *    documentation and/or other materials provided with the distribution.
20f9f848faSopenharmony_ci * 3. All advertising materials mentioning features or use of this software
21f9f848faSopenharmony_ci *    must display the following acknowledgement:
22f9f848faSopenharmony_ci *	This product includes software developed by Bill Paul.
23f9f848faSopenharmony_ci * 4. Neither the name of the author nor the names of any co-contributors
24f9f848faSopenharmony_ci *    may be used to endorse or promote products derived from this software
25f9f848faSopenharmony_ci *    without specific prior written permission.
26f9f848faSopenharmony_ci *
27f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
28f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30f9f848faSopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR
31f9f848faSopenharmony_ci * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32f9f848faSopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33f9f848faSopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
34f9f848faSopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35f9f848faSopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
36f9f848faSopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
37f9f848faSopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38f9f848faSopenharmony_ci */
39f9f848faSopenharmony_ci
40f9f848faSopenharmony_ci/*
41f9f848faSopenharmony_ci * USB Communication Device Class (Ethernet Networking Control Model)
42f9f848faSopenharmony_ci * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
43f9f848faSopenharmony_ci */
44f9f848faSopenharmony_ci
45f9f848faSopenharmony_ci/*
46f9f848faSopenharmony_ci * USB Network Control Model (NCM)
47f9f848faSopenharmony_ci * http://www.usb.org/developers/devclass_docs/NCM10.zip
48f9f848faSopenharmony_ci */
49f9f848faSopenharmony_ci
50f9f848faSopenharmony_ci#include <sys/cdefs.h>
51f9f848faSopenharmony_ci
52f9f848faSopenharmony_ci#include "los_crc32.h"
53f9f848faSopenharmony_ci
54f9f848faSopenharmony_ci#include "implementation/global_implementation.h"
55f9f848faSopenharmony_ci#include "usb_ethernet.h"
56f9f848faSopenharmony_ci#include "if_cdcereg.h"
57f9f848faSopenharmony_ci
58f9f848faSopenharmony_cistatic device_probe_t cdce_probe;
59f9f848faSopenharmony_cistatic device_attach_t cdce_attach;
60f9f848faSopenharmony_cistatic device_detach_t cdce_detach;
61f9f848faSopenharmony_cistatic device_suspend_t cdce_suspend;
62f9f848faSopenharmony_cistatic device_resume_t cdce_resume;
63f9f848faSopenharmony_cistatic usb_handle_request_t cdce_handle_request;
64f9f848faSopenharmony_ci
65f9f848faSopenharmony_cistatic usb_callback_t cdce_bulk_write_callback;
66f9f848faSopenharmony_cistatic usb_callback_t cdce_bulk_read_callback;
67f9f848faSopenharmony_cistatic usb_callback_t cdce_intr_read_callback;
68f9f848faSopenharmony_cistatic usb_callback_t cdce_intr_write_callback;
69f9f848faSopenharmony_ci
70f9f848faSopenharmony_ci#if CDCE_HAVE_NCM
71f9f848faSopenharmony_cistatic usb_callback_t cdce_ncm_bulk_write_callback;
72f9f848faSopenharmony_cistatic usb_callback_t cdce_ncm_bulk_read_callback;
73f9f848faSopenharmony_ci#endif
74f9f848faSopenharmony_ci
75f9f848faSopenharmony_cistatic uether_fn_t cdce_attach_post;
76f9f848faSopenharmony_cistatic uether_fn_t cdce_init;
77f9f848faSopenharmony_cistatic uether_fn_t cdce_stop;
78f9f848faSopenharmony_cistatic uether_fn_t cdce_start;
79f9f848faSopenharmony_cistatic uether_fn_t cdce_setmulti;
80f9f848faSopenharmony_cistatic uether_fn_t cdce_setpromisc;
81f9f848faSopenharmony_ci
82f9f848faSopenharmony_cistatic uint32_t cdce_m_crc32(struct pbuf *, uint32_t, uint32_t);
83f9f848faSopenharmony_ci
84f9f848faSopenharmony_ci#undef USB_DEBUG_VAR
85f9f848faSopenharmony_ci#define	USB_DEBUG_VAR	cdce_debug
86f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG
87f9f848faSopenharmony_cistatic int cdce_debug = 0;
88f9f848faSopenharmony_civoid
89f9f848faSopenharmony_ciusb_cdce_debug_func(int level)
90f9f848faSopenharmony_ci{
91f9f848faSopenharmony_ci	cdce_debug = level;
92f9f848faSopenharmony_ci	PRINTK("The level of usb cdce debug is %d\n", level);
93f9f848faSopenharmony_ci}
94f9f848faSopenharmony_ciDEBUG_MODULE(cdce, usb_cdce_debug_func);
95f9f848faSopenharmony_ci#endif
96f9f848faSopenharmony_ci
97f9f848faSopenharmony_cistatic const struct usb_config cdce_config[CDCE_N_TRANSFER] = {
98f9f848faSopenharmony_ci	[CDCE_BULK_RX] = {
99f9f848faSopenharmony_ci		.type = UE_BULK,
100f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
101f9f848faSopenharmony_ci		.direction = UE_DIR_RX,
102f9f848faSopenharmony_ci		.if_index = 0,
103f9f848faSopenharmony_ci		.frames = CDCE_FRAMES_MAX,
104f9f848faSopenharmony_ci		.bufsize = (CDCE_FRAMES_MAX * MCLBYTES),
105f9f848faSopenharmony_ci		.flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,},
106f9f848faSopenharmony_ci		.callback = cdce_bulk_read_callback,
107f9f848faSopenharmony_ci		.timeout = 0,	/* no timeout */
108f9f848faSopenharmony_ci		.usb_mode = USB_MODE_DUAL,	/* both modes */
109f9f848faSopenharmony_ci	},
110f9f848faSopenharmony_ci
111f9f848faSopenharmony_ci	[CDCE_BULK_TX] = {
112f9f848faSopenharmony_ci		.type = UE_BULK,
113f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
114f9f848faSopenharmony_ci		.direction = UE_DIR_TX,
115f9f848faSopenharmony_ci		.if_index = 0,
116f9f848faSopenharmony_ci		.frames = CDCE_FRAMES_MAX,
117f9f848faSopenharmony_ci		.bufsize = (CDCE_FRAMES_MAX * MCLBYTES),
118f9f848faSopenharmony_ci		.flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,},
119f9f848faSopenharmony_ci		.callback = cdce_bulk_write_callback,
120f9f848faSopenharmony_ci		.timeout = 10000,	/* 10 seconds */
121f9f848faSopenharmony_ci		.usb_mode = USB_MODE_DUAL,	/* both modes */
122f9f848faSopenharmony_ci	},
123f9f848faSopenharmony_ci
124f9f848faSopenharmony_ci	[CDCE_INTR_RX] = {
125f9f848faSopenharmony_ci		.type = UE_INTERRUPT,
126f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
127f9f848faSopenharmony_ci		.direction = UE_DIR_RX,
128f9f848faSopenharmony_ci		.if_index = 1,
129f9f848faSopenharmony_ci		.bufsize = CDCE_IND_SIZE_MAX,
130f9f848faSopenharmony_ci		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,},
131f9f848faSopenharmony_ci		.callback = cdce_intr_read_callback,
132f9f848faSopenharmony_ci		.timeout = 0,
133f9f848faSopenharmony_ci		.usb_mode = USB_MODE_HOST,
134f9f848faSopenharmony_ci	},
135f9f848faSopenharmony_ci
136f9f848faSopenharmony_ci	[CDCE_INTR_TX] = {
137f9f848faSopenharmony_ci		.type = UE_INTERRUPT,
138f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
139f9f848faSopenharmony_ci		.direction = UE_DIR_TX,
140f9f848faSopenharmony_ci		.if_index = 1,
141f9f848faSopenharmony_ci		.bufsize = CDCE_IND_SIZE_MAX,
142f9f848faSopenharmony_ci		.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
143f9f848faSopenharmony_ci		.callback = cdce_intr_write_callback,
144f9f848faSopenharmony_ci		.timeout = 10000,	/* 10 seconds */
145f9f848faSopenharmony_ci		.usb_mode = USB_MODE_DEVICE,
146f9f848faSopenharmony_ci	},
147f9f848faSopenharmony_ci};
148f9f848faSopenharmony_ci
149f9f848faSopenharmony_ci#if CDCE_HAVE_NCM
150f9f848faSopenharmony_cistatic const struct usb_config cdce_ncm_config[CDCE_N_TRANSFER] = {
151f9f848faSopenharmony_ci	[CDCE_BULK_RX] = {
152f9f848faSopenharmony_ci		.type = UE_BULK,
153f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
154f9f848faSopenharmony_ci		.direction = UE_DIR_RX,
155f9f848faSopenharmony_ci		.if_index = 0,
156f9f848faSopenharmony_ci		.frames = CDCE_NCM_RX_FRAMES_MAX,
157f9f848faSopenharmony_ci		.bufsize = (CDCE_NCM_RX_FRAMES_MAX * CDCE_NCM_RX_MAXLEN),
158f9f848faSopenharmony_ci		.flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,},
159f9f848faSopenharmony_ci		.callback = cdce_ncm_bulk_read_callback,
160f9f848faSopenharmony_ci		.timeout = 0,	/* no timeout */
161f9f848faSopenharmony_ci		.usb_mode = USB_MODE_DUAL,	/* both modes */
162f9f848faSopenharmony_ci	},
163f9f848faSopenharmony_ci
164f9f848faSopenharmony_ci	[CDCE_BULK_TX] = {
165f9f848faSopenharmony_ci		.type = UE_BULK,
166f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
167f9f848faSopenharmony_ci		.direction = UE_DIR_TX,
168f9f848faSopenharmony_ci		.if_index = 0,
169f9f848faSopenharmony_ci		.frames = CDCE_NCM_TX_FRAMES_MAX,
170f9f848faSopenharmony_ci		.bufsize = (CDCE_NCM_TX_FRAMES_MAX * CDCE_NCM_TX_MAXLEN),
171f9f848faSopenharmony_ci		.flags = {.pipe_bof = 1,},
172f9f848faSopenharmony_ci		.callback = cdce_ncm_bulk_write_callback,
173f9f848faSopenharmony_ci		.timeout = 10000,	/* 10 seconds */
174f9f848faSopenharmony_ci		.usb_mode = USB_MODE_DUAL,	/* both modes */
175f9f848faSopenharmony_ci	},
176f9f848faSopenharmony_ci
177f9f848faSopenharmony_ci	[CDCE_INTR_RX] = {
178f9f848faSopenharmony_ci		.type = UE_INTERRUPT,
179f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
180f9f848faSopenharmony_ci		.direction = UE_DIR_RX,
181f9f848faSopenharmony_ci		.if_index = 1,
182f9f848faSopenharmony_ci		.bufsize = CDCE_IND_SIZE_MAX,
183f9f848faSopenharmony_ci		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,},
184f9f848faSopenharmony_ci		.callback = cdce_intr_read_callback,
185f9f848faSopenharmony_ci		.timeout = 0,
186f9f848faSopenharmony_ci		.usb_mode = USB_MODE_HOST,
187f9f848faSopenharmony_ci	},
188f9f848faSopenharmony_ci
189f9f848faSopenharmony_ci	[CDCE_INTR_TX] = {
190f9f848faSopenharmony_ci		.type = UE_INTERRUPT,
191f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
192f9f848faSopenharmony_ci		.direction = UE_DIR_TX,
193f9f848faSopenharmony_ci		.if_index = 1,
194f9f848faSopenharmony_ci		.bufsize = CDCE_IND_SIZE_MAX,
195f9f848faSopenharmony_ci		.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
196f9f848faSopenharmony_ci		.callback = cdce_intr_write_callback,
197f9f848faSopenharmony_ci		.timeout = 10000,	/* 10 seconds */
198f9f848faSopenharmony_ci		.usb_mode = USB_MODE_DEVICE,
199f9f848faSopenharmony_ci	},
200f9f848faSopenharmony_ci};
201f9f848faSopenharmony_ci#endif
202f9f848faSopenharmony_ci
203f9f848faSopenharmony_cistatic device_method_t cdce_methods[] = {
204f9f848faSopenharmony_ci	/* USB interface */
205f9f848faSopenharmony_ci	DEVMETHOD(usb_handle_request, cdce_handle_request),
206f9f848faSopenharmony_ci
207f9f848faSopenharmony_ci	/* Device interface */
208f9f848faSopenharmony_ci	DEVMETHOD(device_probe, cdce_probe),
209f9f848faSopenharmony_ci	DEVMETHOD(device_attach, cdce_attach),
210f9f848faSopenharmony_ci	DEVMETHOD(device_detach, cdce_detach),
211f9f848faSopenharmony_ci	DEVMETHOD(device_suspend, cdce_suspend),
212f9f848faSopenharmony_ci	DEVMETHOD(device_resume, cdce_resume),
213f9f848faSopenharmony_ci
214f9f848faSopenharmony_ci	DEVMETHOD_END
215f9f848faSopenharmony_ci};
216f9f848faSopenharmony_ci
217f9f848faSopenharmony_cistatic driver_t cdce_driver = {
218f9f848faSopenharmony_ci	.name = "cdce",
219f9f848faSopenharmony_ci	.methods = cdce_methods,
220f9f848faSopenharmony_ci	.size = sizeof(struct cdce_softc),
221f9f848faSopenharmony_ci};
222f9f848faSopenharmony_ci
223f9f848faSopenharmony_cistatic devclass_t cdce_devclass;
224f9f848faSopenharmony_ci
225f9f848faSopenharmony_ciDRIVER_MODULE(cdce, uhub, cdce_driver, cdce_devclass, NULL, 0);
226f9f848faSopenharmony_ci
227f9f848faSopenharmony_cistatic const struct usb_ether_methods cdce_ue_methods = {
228f9f848faSopenharmony_ci	.ue_attach_post = cdce_attach_post,
229f9f848faSopenharmony_ci	.ue_start = cdce_start,
230f9f848faSopenharmony_ci	.ue_init = cdce_init,
231f9f848faSopenharmony_ci	.ue_stop = cdce_stop,
232f9f848faSopenharmony_ci	.ue_setmulti = cdce_setmulti,
233f9f848faSopenharmony_ci	.ue_setpromisc = cdce_setpromisc,
234f9f848faSopenharmony_ci};
235f9f848faSopenharmony_ci
236f9f848faSopenharmony_cistatic const STRUCT_USB_HOST_ID cdce_host_devs[] = {
237f9f848faSopenharmony_ci
238f9f848faSopenharmony_ci};
239f9f848faSopenharmony_ci
240f9f848faSopenharmony_cistatic const STRUCT_USB_DUAL_ID cdce_dual_devs[] = {
241f9f848faSopenharmony_ci	{USB_IF_CSI(UICLASS_CDC, UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0)},
242f9f848faSopenharmony_ci	{USB_IF_CSI(UICLASS_CDC, UISUBCLASS_MOBILE_DIRECT_LINE_MODEL, 0)},
243f9f848faSopenharmony_ci	{USB_IF_CSI(UICLASS_CDC, UISUBCLASS_NETWORK_CONTROL_MODEL, 0)},
244f9f848faSopenharmony_ci};
245f9f848faSopenharmony_ci
246f9f848faSopenharmony_ci#if CDCE_HAVE_NCM
247f9f848faSopenharmony_ci/*------------------------------------------------------------------------*
248f9f848faSopenharmony_ci *	cdce_ncm_init
249f9f848faSopenharmony_ci *
250f9f848faSopenharmony_ci * Return values:
251f9f848faSopenharmony_ci * 0: Success
252f9f848faSopenharmony_ci * Else: Failure
253f9f848faSopenharmony_ci *------------------------------------------------------------------------*/
254f9f848faSopenharmony_cistatic uint8_t
255f9f848faSopenharmony_cicdce_ncm_init(struct cdce_softc *sc)
256f9f848faSopenharmony_ci{
257f9f848faSopenharmony_ci	struct usb_ncm_parameters temp;
258f9f848faSopenharmony_ci	struct usb_device_request req;
259f9f848faSopenharmony_ci	struct usb_ncm_func_descriptor *ufd;
260f9f848faSopenharmony_ci	uint8_t value[8];
261f9f848faSopenharmony_ci	int err;
262f9f848faSopenharmony_ci
263f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
264f9f848faSopenharmony_ci
265f9f848faSopenharmony_ci	ufd = usbd_find_descriptor(sc->sc_ue.ue_udev, NULL,
266f9f848faSopenharmony_ci							    sc->sc_ifaces_index[1], UDESC_CS_INTERFACE, 0xFF,
267f9f848faSopenharmony_ci							    UCDC_NCM_FUNC_DESC_SUBTYPE, 0xFF);
268f9f848faSopenharmony_ci
269f9f848faSopenharmony_ci	/* verify length of NCM functional descriptor */
270f9f848faSopenharmony_ci	if (ufd != NULL) {
271f9f848faSopenharmony_ci		if (ufd->bLength < sizeof(*ufd))
272f9f848faSopenharmony_ci			ufd = NULL;
273f9f848faSopenharmony_ci		else
274f9f848faSopenharmony_ci			DPRINTFN(1, "Found NCM functional descriptor.\n");
275f9f848faSopenharmony_ci	}
276f9f848faSopenharmony_ci
277f9f848faSopenharmony_ci	req.bmRequestType = UT_READ_CLASS_INTERFACE;
278f9f848faSopenharmony_ci	req.bRequest = UCDC_NCM_GET_NTB_PARAMETERS;
279f9f848faSopenharmony_ci	USETW(req.wValue, 0);
280f9f848faSopenharmony_ci	req.wIndex[0] = sc->sc_ifaces_index[1];
281f9f848faSopenharmony_ci	req.wIndex[1] = 0;
282f9f848faSopenharmony_ci	USETW(req.wLength, sizeof(temp));
283f9f848faSopenharmony_ci
284f9f848faSopenharmony_ci	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
285f9f848faSopenharmony_ci							    &temp, 0, NULL, 1000 /* ms */);
286f9f848faSopenharmony_ci	if (err){
287f9f848faSopenharmony_ci		DPRINTFN(1, "request error!\n");
288f9f848faSopenharmony_ci		return (1);
289f9f848faSopenharmony_ci	}
290f9f848faSopenharmony_ci	/* Read correct set of parameters according to device mode */
291f9f848faSopenharmony_ci	DPRINTFN(1, "line %d!\n",__LINE__);
292f9f848faSopenharmony_ci
293f9f848faSopenharmony_ci	if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) {
294f9f848faSopenharmony_ci		sc->sc_ncm.rx_max = UGETDW(temp.dwNtbInMaxSize);
295f9f848faSopenharmony_ci		sc->sc_ncm.tx_max = UGETDW(temp.dwNtbOutMaxSize);
296f9f848faSopenharmony_ci		sc->sc_ncm.tx_remainder = UGETW(temp.wNdpOutPayloadRemainder);
297f9f848faSopenharmony_ci		sc->sc_ncm.tx_modulus = UGETW(temp.wNdpOutDivisor);
298f9f848faSopenharmony_ci		sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpOutAlignment);
299f9f848faSopenharmony_ci		sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams);
300f9f848faSopenharmony_ci	} else {
301f9f848faSopenharmony_ci		sc->sc_ncm.rx_max = UGETDW(temp.dwNtbOutMaxSize);
302f9f848faSopenharmony_ci		sc->sc_ncm.tx_max = UGETDW(temp.dwNtbInMaxSize);
303f9f848faSopenharmony_ci		sc->sc_ncm.tx_remainder = UGETW(temp.wNdpInPayloadRemainder);
304f9f848faSopenharmony_ci		sc->sc_ncm.tx_modulus = UGETW(temp.wNdpInDivisor);
305f9f848faSopenharmony_ci		sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpInAlignment);
306f9f848faSopenharmony_ci		sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams);
307f9f848faSopenharmony_ci	}
308f9f848faSopenharmony_ci
309f9f848faSopenharmony_ci	/* Verify maximum receive length */
310f9f848faSopenharmony_ci
311f9f848faSopenharmony_ci	if ((sc->sc_ncm.rx_max < 32) ||
312f9f848faSopenharmony_ci	    (sc->sc_ncm.rx_max > CDCE_NCM_RX_MAXLEN)) {
313f9f848faSopenharmony_ci		DPRINTFN(1, "Using default maximum receive length\n");
314f9f848faSopenharmony_ci		sc->sc_ncm.rx_max = CDCE_NCM_RX_MAXLEN;
315f9f848faSopenharmony_ci	}
316f9f848faSopenharmony_ci
317f9f848faSopenharmony_ci	/* Verify maximum transmit length */
318f9f848faSopenharmony_ci
319f9f848faSopenharmony_ci	if ((sc->sc_ncm.tx_max < 32) ||
320f9f848faSopenharmony_ci	    (sc->sc_ncm.tx_max > CDCE_NCM_TX_MAXLEN)) {
321f9f848faSopenharmony_ci		DPRINTFN(1, "Using default maximum transmit length\n");
322f9f848faSopenharmony_ci		sc->sc_ncm.tx_max = CDCE_NCM_TX_MAXLEN;
323f9f848faSopenharmony_ci	}
324f9f848faSopenharmony_ci
325f9f848faSopenharmony_ci	/*
326f9f848faSopenharmony_ci	 * Verify that the structure alignment is:
327f9f848faSopenharmony_ci	 * - power of two
328f9f848faSopenharmony_ci	 * - not greater than the maximum transmit length
329f9f848faSopenharmony_ci	 * - not less than four bytes
330f9f848faSopenharmony_ci	 */
331f9f848faSopenharmony_ci	if ((sc->sc_ncm.tx_struct_align < 4) ||
332f9f848faSopenharmony_ci	    (sc->sc_ncm.tx_struct_align !=
333f9f848faSopenharmony_ci	    ((-sc->sc_ncm.tx_struct_align) & sc->sc_ncm.tx_struct_align)) ||
334f9f848faSopenharmony_ci	    (sc->sc_ncm.tx_struct_align >= sc->sc_ncm.tx_max)) {
335f9f848faSopenharmony_ci		DPRINTFN(1, "Using default other alignment: 4 bytes\n");
336f9f848faSopenharmony_ci		sc->sc_ncm.tx_struct_align = 4;
337f9f848faSopenharmony_ci	}
338f9f848faSopenharmony_ci
339f9f848faSopenharmony_ci	/*
340f9f848faSopenharmony_ci	 * Verify that the payload alignment is:
341f9f848faSopenharmony_ci	 * - power of two
342f9f848faSopenharmony_ci	 * - not greater than the maximum transmit length
343f9f848faSopenharmony_ci	 * - not less than four bytes
344f9f848faSopenharmony_ci	 */
345f9f848faSopenharmony_ci	if ((sc->sc_ncm.tx_modulus < 4) ||
346f9f848faSopenharmony_ci	    (sc->sc_ncm.tx_modulus !=
347f9f848faSopenharmony_ci	    ((-sc->sc_ncm.tx_modulus) & sc->sc_ncm.tx_modulus)) ||
348f9f848faSopenharmony_ci	    (sc->sc_ncm.tx_modulus >= sc->sc_ncm.tx_max)) {
349f9f848faSopenharmony_ci		DPRINTFN(1, "Using default transmit modulus: 4 bytes\n");
350f9f848faSopenharmony_ci		sc->sc_ncm.tx_modulus = 4;
351f9f848faSopenharmony_ci	}
352f9f848faSopenharmony_ci
353f9f848faSopenharmony_ci	/* Verify that the payload remainder */
354f9f848faSopenharmony_ci
355f9f848faSopenharmony_ci	if ((sc->sc_ncm.tx_remainder >= sc->sc_ncm.tx_modulus)) {
356f9f848faSopenharmony_ci		DPRINTFN(1, "Using default transmit remainder: 0 bytes\n");
357f9f848faSopenharmony_ci		sc->sc_ncm.tx_remainder = 0;
358f9f848faSopenharmony_ci	}
359f9f848faSopenharmony_ci
360f9f848faSopenharmony_ci	/*
361f9f848faSopenharmony_ci	 * Offset the TX remainder so that IP packet payload starts at
362f9f848faSopenharmony_ci	 * the tx_modulus. This is not too clear in the specification.
363f9f848faSopenharmony_ci	 */
364f9f848faSopenharmony_ci
365f9f848faSopenharmony_ci	sc->sc_ncm.tx_remainder =
366f9f848faSopenharmony_ci	    (sc->sc_ncm.tx_remainder - ETHER_HDR_LEN) &
367f9f848faSopenharmony_ci	    (sc->sc_ncm.tx_modulus - 1);
368f9f848faSopenharmony_ci
369f9f848faSopenharmony_ci	/* Verify max datagrams */
370f9f848faSopenharmony_ci
371f9f848faSopenharmony_ci	if (sc->sc_ncm.tx_nframe == 0 ||
372f9f848faSopenharmony_ci	    sc->sc_ncm.tx_nframe > (CDCE_NCM_SUBFRAMES_MAX - 1)) {
373f9f848faSopenharmony_ci		DPRINTFN(1, "Using default max "
374f9f848faSopenharmony_ci		    "subframes: %u units\n", CDCE_NCM_SUBFRAMES_MAX - 1);
375f9f848faSopenharmony_ci		/* need to reserve one entry for zero padding */
376f9f848faSopenharmony_ci		sc->sc_ncm.tx_nframe = (CDCE_NCM_SUBFRAMES_MAX - 1);
377f9f848faSopenharmony_ci	}
378f9f848faSopenharmony_ci
379f9f848faSopenharmony_ci	/* Additional configuration, will fail in device side mode, which is OK. */
380f9f848faSopenharmony_ci
381f9f848faSopenharmony_ci	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
382f9f848faSopenharmony_ci	req.bRequest = UCDC_NCM_SET_NTB_INPUT_SIZE;
383f9f848faSopenharmony_ci	USETW(req.wValue, 0);
384f9f848faSopenharmony_ci	req.wIndex[0] = sc->sc_ifaces_index[1];
385f9f848faSopenharmony_ci	req.wIndex[1] = 0;
386f9f848faSopenharmony_ci
387f9f848faSopenharmony_ci	if ((ufd != NULL) &&
388f9f848faSopenharmony_ci	    (ufd->bmNetworkCapabilities & UCDC_NCM_CAP_MAX_DGRAM)) {
389f9f848faSopenharmony_ci		USETW(req.wLength, 8);
390f9f848faSopenharmony_ci		USETDW(value, sc->sc_ncm.rx_max);
391f9f848faSopenharmony_ci		USETW(value + 4, (CDCE_NCM_SUBFRAMES_MAX - 1));
392f9f848faSopenharmony_ci		USETW(value + 6, 0);
393f9f848faSopenharmony_ci	} else {
394f9f848faSopenharmony_ci		USETW(req.wLength, 4);
395f9f848faSopenharmony_ci		USETDW(value, sc->sc_ncm.rx_max);
396f9f848faSopenharmony_ci	}
397f9f848faSopenharmony_ci
398f9f848faSopenharmony_ci	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
399f9f848faSopenharmony_ci							    &value, 0, NULL, 1000 /* ms */);
400f9f848faSopenharmony_ci	if (err) {
401f9f848faSopenharmony_ci		DPRINTFN(1, "Setting input size "
402f9f848faSopenharmony_ci			    "to %u failed.\n", sc->sc_ncm.rx_max);
403f9f848faSopenharmony_ci	}
404f9f848faSopenharmony_ci
405f9f848faSopenharmony_ci	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
406f9f848faSopenharmony_ci	req.bRequest = UCDC_NCM_SET_CRC_MODE;
407f9f848faSopenharmony_ci	USETW(req.wValue, 0);	/* no CRC */
408f9f848faSopenharmony_ci	req.wIndex[0] = sc->sc_ifaces_index[1];
409f9f848faSopenharmony_ci	req.wIndex[1] = 0;
410f9f848faSopenharmony_ci	USETW(req.wLength, 0);
411f9f848faSopenharmony_ci
412f9f848faSopenharmony_ci	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
413f9f848faSopenharmony_ci	    NULL, 0, NULL, 1000 /* ms */);
414f9f848faSopenharmony_ci	if (err) {
415f9f848faSopenharmony_ci		DPRINTFN(1, "Setting CRC mode to off failed.\n");
416f9f848faSopenharmony_ci	}
417f9f848faSopenharmony_ci
418f9f848faSopenharmony_ci	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
419f9f848faSopenharmony_ci	req.bRequest = UCDC_NCM_SET_NTB_FORMAT;
420f9f848faSopenharmony_ci	USETW(req.wValue, 0);	/* NTB-16 */
421f9f848faSopenharmony_ci	req.wIndex[0] = sc->sc_ifaces_index[1];
422f9f848faSopenharmony_ci	req.wIndex[1] = 0;
423f9f848faSopenharmony_ci	USETW(req.wLength, 0);
424f9f848faSopenharmony_ci
425f9f848faSopenharmony_ci	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
426f9f848faSopenharmony_ci	    NULL, 0, NULL, 1000 /* ms */);
427f9f848faSopenharmony_ci	if (err) {
428f9f848faSopenharmony_ci		DPRINTFN(1, "Setting NTB format to 16-bit failed.\n");
429f9f848faSopenharmony_ci	}
430f9f848faSopenharmony_ci
431f9f848faSopenharmony_ci	DPRINTFN(1, " -->end!\n");
432f9f848faSopenharmony_ci
433f9f848faSopenharmony_ci	return (0);		/* success */
434f9f848faSopenharmony_ci}
435f9f848faSopenharmony_ci#endif
436f9f848faSopenharmony_ci
437f9f848faSopenharmony_cistatic int
438f9f848faSopenharmony_cicdce_probe(device_t dev)
439f9f848faSopenharmony_ci{
440f9f848faSopenharmony_ci	struct usb_attach_arg *uaa = (struct usb_attach_arg *)device_get_ivars(dev);
441f9f848faSopenharmony_ci	int error;
442f9f848faSopenharmony_ci
443f9f848faSopenharmony_ci	error = usbd_lookup_id_by_uaa(cdce_host_devs, sizeof(cdce_host_devs), uaa);
444f9f848faSopenharmony_ci
445f9f848faSopenharmony_ci	if (error)
446f9f848faSopenharmony_ci		error = usbd_lookup_id_by_uaa(cdce_dual_devs, sizeof(cdce_dual_devs), uaa);
447f9f848faSopenharmony_ci	return (error);
448f9f848faSopenharmony_ci}
449f9f848faSopenharmony_ci
450f9f848faSopenharmony_cistatic void
451f9f848faSopenharmony_cicdce_attach_post(struct usb_ether *ue)
452f9f848faSopenharmony_ci{
453f9f848faSopenharmony_ci	/* no-op */
454f9f848faSopenharmony_ci	return;
455f9f848faSopenharmony_ci}
456f9f848faSopenharmony_ci
457f9f848faSopenharmony_cistatic int
458f9f848faSopenharmony_cicdce_attach(device_t dev)
459f9f848faSopenharmony_ci{
460f9f848faSopenharmony_ci	struct cdce_softc *sc = (struct cdce_softc *)device_get_softc(dev);
461f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
462f9f848faSopenharmony_ci	struct usb_attach_arg *uaa = (struct usb_attach_arg *)device_get_ivars(dev);
463f9f848faSopenharmony_ci	struct usb_interface *iface;
464f9f848faSopenharmony_ci	const struct usb_cdc_union_descriptor *ud;
465f9f848faSopenharmony_ci	const struct usb_interface_descriptor *id;
466f9f848faSopenharmony_ci	const struct usb_cdc_ethernet_descriptor *ued;
467f9f848faSopenharmony_ci	const struct usb_config *pcfg;
468f9f848faSopenharmony_ci	uint32_t seed;
469f9f848faSopenharmony_ci	usb_error_t error;
470f9f848faSopenharmony_ci	uint8_t i;
471f9f848faSopenharmony_ci	uint8_t data_iface_no;
472f9f848faSopenharmony_ci	char eaddr_str[5 * NETIF_MAX_HWADDR_LEN];	/* approx */
473f9f848faSopenharmony_ci
474f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
475f9f848faSopenharmony_ci
476f9f848faSopenharmony_ci	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
477f9f848faSopenharmony_ci	sc->sc_ue.ue_udev = uaa->device;
478f9f848faSopenharmony_ci
479f9f848faSopenharmony_ci	device_set_usb_desc(dev);
480f9f848faSopenharmony_ci
481f9f848faSopenharmony_ci	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
482f9f848faSopenharmony_ci
483f9f848faSopenharmony_ci	ud = (const struct usb_cdc_union_descriptor *)usbd_find_descriptor
484f9f848faSopenharmony_ci	    (uaa->device, NULL, uaa->info.bIfaceIndex, UDESC_CS_INTERFACE,
485f9f848faSopenharmony_ci	    0xFF, UDESCSUB_CDC_UNION, 0xFF);
486f9f848faSopenharmony_ci
487f9f848faSopenharmony_ci	if ((ud == NULL) || (ud->bLength < sizeof(*ud)) ||
488f9f848faSopenharmony_ci	    (sc->sc_flags & CDCE_FLAG_NO_UNION)) {
489f9f848faSopenharmony_ci		DPRINTFN(1, "No union descriptor!\n");
490f9f848faSopenharmony_ci		sc->sc_ifaces_index[0] = uaa->info.bIfaceIndex;
491f9f848faSopenharmony_ci		sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex;
492f9f848faSopenharmony_ci		goto alloc_transfers;
493f9f848faSopenharmony_ci	}
494f9f848faSopenharmony_ci	data_iface_no = ud->bSlaveInterface[0];
495f9f848faSopenharmony_ci	DPRINTFN(1, "data_iface_no = %d!\n", data_iface_no);
496f9f848faSopenharmony_ci
497f9f848faSopenharmony_ci	for (i = 0;; i++) {
498f9f848faSopenharmony_ci		iface = usbd_get_iface(uaa->device, i);
499f9f848faSopenharmony_ci
500f9f848faSopenharmony_ci		if (iface) {
501f9f848faSopenharmony_ci			id = usbd_get_interface_descriptor(iface);
502f9f848faSopenharmony_ci
503f9f848faSopenharmony_ci			if (id && (id->bInterfaceNumber == data_iface_no)) {
504f9f848faSopenharmony_ci				sc->sc_ifaces_index[0] = i;
505f9f848faSopenharmony_ci				sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex;
506f9f848faSopenharmony_ci				DPRINTFN(1, "index 0 = %d, index 1 = %d!\n", i, uaa->info.bIfaceIndex);
507f9f848faSopenharmony_ci				usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
508f9f848faSopenharmony_ci				break;
509f9f848faSopenharmony_ci			}
510f9f848faSopenharmony_ci		} else {
511f9f848faSopenharmony_ci			device_printf(dev, "no data interface found\n");
512f9f848faSopenharmony_ci			goto detach;
513f9f848faSopenharmony_ci		}
514f9f848faSopenharmony_ci	}
515f9f848faSopenharmony_ci
516f9f848faSopenharmony_ci	/*
517f9f848faSopenharmony_ci	 * <quote>
518f9f848faSopenharmony_ci	 *
519f9f848faSopenharmony_ci	 *  The Data Class interface of a networking device shall have
520f9f848faSopenharmony_ci	 *  a minimum of two interface settings. The first setting
521f9f848faSopenharmony_ci	 *  (the default interface setting) includes no endpoints and
522f9f848faSopenharmony_ci	 *  therefore no networking traffic is exchanged whenever the
523f9f848faSopenharmony_ci	 *  default interface setting is selected. One or more
524f9f848faSopenharmony_ci	 *  additional interface settings are used for normal
525f9f848faSopenharmony_ci	 *  operation, and therefore each includes a pair of endpoints
526f9f848faSopenharmony_ci	 *  (one IN, and one OUT) to exchange network traffic. Select
527f9f848faSopenharmony_ci	 *  an alternate interface setting to initialize the network
528f9f848faSopenharmony_ci	 *  aspects of the device and to enable the exchange of
529f9f848faSopenharmony_ci	 *  network traffic.
530f9f848faSopenharmony_ci	 *
531f9f848faSopenharmony_ci	 * </quote>
532f9f848faSopenharmony_ci	 *
533f9f848faSopenharmony_ci	 * Some devices, most notably cable modems, include interface
534f9f848faSopenharmony_ci	 * settings that have no IN or OUT endpoint, therefore loop
535f9f848faSopenharmony_ci	 * through the list of all available interface settings
536f9f848faSopenharmony_ci	 * looking for one with both IN and OUT endpoints.
537f9f848faSopenharmony_ci	 */
538f9f848faSopenharmony_ci
539f9f848faSopenharmony_cialloc_transfers:
540f9f848faSopenharmony_ci
541f9f848faSopenharmony_ci	pcfg = cdce_config;	/* Default Configuration */
542f9f848faSopenharmony_ci
543f9f848faSopenharmony_ci	for (i = 0; i != 32; i++) {
544f9f848faSopenharmony_ci		error = usbd_set_alt_interface_index(uaa->device,
545f9f848faSopenharmony_ci		    sc->sc_ifaces_index[0], i);
546f9f848faSopenharmony_ci		if (error) {
547f9f848faSopenharmony_ci			break;
548f9f848faSopenharmony_ci		}
549f9f848faSopenharmony_ci
550f9f848faSopenharmony_ci#if CDCE_HAVE_NCM
551f9f848faSopenharmony_ci		if ((i == 0) && (cdce_ncm_init(sc) == 0))
552f9f848faSopenharmony_ci			pcfg = cdce_ncm_config;
553f9f848faSopenharmony_ci#endif
554f9f848faSopenharmony_ci		error = usbd_transfer_setup(uaa->device,
555f9f848faSopenharmony_ci		    sc->sc_ifaces_index, sc->sc_xfer,
556f9f848faSopenharmony_ci		    pcfg, CDCE_N_TRANSFER, sc, &sc->sc_mtx);
557f9f848faSopenharmony_ci
558f9f848faSopenharmony_ci		if (error == 0) {
559f9f848faSopenharmony_ci			break;
560f9f848faSopenharmony_ci		}
561f9f848faSopenharmony_ci	}
562f9f848faSopenharmony_ci
563f9f848faSopenharmony_ci	if (error || (i == 32)) {
564f9f848faSopenharmony_ci		device_printf(dev, "No valid alternate "
565f9f848faSopenharmony_ci		    "setting found\n");
566f9f848faSopenharmony_ci		goto detach;
567f9f848faSopenharmony_ci	}
568f9f848faSopenharmony_ci
569f9f848faSopenharmony_ci	ued = (const struct usb_cdc_ethernet_descriptor *)usbd_find_descriptor
570f9f848faSopenharmony_ci	    (uaa->device, NULL, uaa->info.bIfaceIndex, UDESC_CS_INTERFACE,
571f9f848faSopenharmony_ci	    0xFF, UDESCSUB_CDC_ENF, 0xFF);
572f9f848faSopenharmony_ci
573f9f848faSopenharmony_ci	if ((ued == NULL) || (ued->bLength < sizeof(*ued))) {
574f9f848faSopenharmony_ci		error = USB_ERR_INVAL;
575f9f848faSopenharmony_ci	} else {
576f9f848faSopenharmony_ci		error = usbd_req_get_string_any(uaa->device, NULL,
577f9f848faSopenharmony_ci		    eaddr_str, sizeof(eaddr_str), ued->iMacAddress);
578f9f848faSopenharmony_ci	}
579f9f848faSopenharmony_ci
580f9f848faSopenharmony_ci	if (error) {
581f9f848faSopenharmony_ci		/* fake MAC address */
582f9f848faSopenharmony_ci
583f9f848faSopenharmony_ci		device_printf(dev, "faking MAC address\n");
584f9f848faSopenharmony_ci		seed = CUR_TICKS;
585f9f848faSopenharmony_ci		(void)memcpy_s(&sc->sc_ue.ue_eaddr[1], (NETIF_MAX_HWADDR_LEN - 2), &seed, sizeof(uint32_t));
586f9f848faSopenharmony_ci		sc->sc_ue.ue_eaddr[0] = 0x2a;
587f9f848faSopenharmony_ci		sc->sc_ue.ue_eaddr[5] = device_get_unit(dev);
588f9f848faSopenharmony_ci
589f9f848faSopenharmony_ci	} else {
590f9f848faSopenharmony_ci		(void)memset_s(sc->sc_ue.ue_eaddr, sizeof(sc->sc_ue.ue_eaddr), 0, sizeof(sc->sc_ue.ue_eaddr));
591f9f848faSopenharmony_ci
592f9f848faSopenharmony_ci		for (i = 0; i != (NETIF_MAX_HWADDR_LEN * 2); i++) {
593f9f848faSopenharmony_ci			char c = eaddr_str[i];
594f9f848faSopenharmony_ci
595f9f848faSopenharmony_ci			if (('0' <= c) && (c <= '9'))
596f9f848faSopenharmony_ci				c -= '0';
597f9f848faSopenharmony_ci			else if (c != 0)
598f9f848faSopenharmony_ci				c -= 'A' - 10;
599f9f848faSopenharmony_ci			else
600f9f848faSopenharmony_ci				break;
601f9f848faSopenharmony_ci
602f9f848faSopenharmony_ci			c &= 0xf;
603f9f848faSopenharmony_ci
604f9f848faSopenharmony_ci			if ((i & 1) == 0)
605f9f848faSopenharmony_ci				c <<= 4;
606f9f848faSopenharmony_ci			sc->sc_ue.ue_eaddr[i / 2] |= c;
607f9f848faSopenharmony_ci		}
608f9f848faSopenharmony_ci
609f9f848faSopenharmony_ci		if (uaa->usb_mode == USB_MODE_DEVICE) {
610f9f848faSopenharmony_ci			/*
611f9f848faSopenharmony_ci			 * Do not use the same MAC address like the peer !
612f9f848faSopenharmony_ci			 */
613f9f848faSopenharmony_ci			sc->sc_ue.ue_eaddr[5] ^= 0xFF;
614f9f848faSopenharmony_ci		}
615f9f848faSopenharmony_ci	}
616f9f848faSopenharmony_ci
617f9f848faSopenharmony_ci	ue->ue_sc = sc;
618f9f848faSopenharmony_ci	ue->ue_dev = dev;
619f9f848faSopenharmony_ci	ue->ue_udev = uaa->device;
620f9f848faSopenharmony_ci	ue->ue_mtx = &sc->sc_mtx;
621f9f848faSopenharmony_ci	ue->ue_methods = &cdce_ue_methods;
622f9f848faSopenharmony_ci
623f9f848faSopenharmony_ci	error = (usb_error_t)uether_ifattach(ue);
624f9f848faSopenharmony_ci	if (error) {
625f9f848faSopenharmony_ci		device_printf(dev, "could not attach interface\n");
626f9f848faSopenharmony_ci		goto detach;
627f9f848faSopenharmony_ci	}
628f9f848faSopenharmony_ci	return (0);			/* success */
629f9f848faSopenharmony_ci
630f9f848faSopenharmony_cidetach:
631f9f848faSopenharmony_ci	(void)cdce_detach(dev);
632f9f848faSopenharmony_ci	return (ENXIO);			/* failure */
633f9f848faSopenharmony_ci}
634f9f848faSopenharmony_ci
635f9f848faSopenharmony_cistatic int
636f9f848faSopenharmony_cicdce_detach(device_t dev)
637f9f848faSopenharmony_ci{
638f9f848faSopenharmony_ci	struct cdce_softc *sc = (struct cdce_softc *)device_get_softc(dev);
639f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
640f9f848faSopenharmony_ci
641f9f848faSopenharmony_ci	/* stop all USB transfers first */
642f9f848faSopenharmony_ci	usbd_transfer_unsetup(sc->sc_xfer, CDCE_N_TRANSFER);
643f9f848faSopenharmony_ci	uether_ifdetach(ue);
644f9f848faSopenharmony_ci	mtx_destroy(&sc->sc_mtx);
645f9f848faSopenharmony_ci
646f9f848faSopenharmony_ci	return (0);
647f9f848faSopenharmony_ci}
648f9f848faSopenharmony_ci
649f9f848faSopenharmony_cistatic void
650f9f848faSopenharmony_cicdce_start(struct usb_ether *ue)
651f9f848faSopenharmony_ci{
652f9f848faSopenharmony_ci	struct cdce_softc *sc = (struct cdce_softc *)uether_getsc(ue);
653f9f848faSopenharmony_ci
654f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
655f9f848faSopenharmony_ci	/*
656f9f848faSopenharmony_ci	 * Start the USB transfers, if not already started:
657f9f848faSopenharmony_ci	 */
658f9f848faSopenharmony_ci	usbd_transfer_start(sc->sc_xfer[CDCE_BULK_TX]);
659f9f848faSopenharmony_ci	usbd_transfer_start(sc->sc_xfer[CDCE_BULK_RX]);
660f9f848faSopenharmony_ci}
661f9f848faSopenharmony_ci
662f9f848faSopenharmony_cistatic void
663f9f848faSopenharmony_cicdce_free_queue(struct pbuf **ppm, uint8_t n)
664f9f848faSopenharmony_ci{
665f9f848faSopenharmony_ci	uint8_t x;
666f9f848faSopenharmony_ci	for (x = 0; x != n; x++) {
667f9f848faSopenharmony_ci		if (ppm[x] != NULL) {
668f9f848faSopenharmony_ci			uether_freebuf(ppm[x]);
669f9f848faSopenharmony_ci			ppm[x] = NULL;
670f9f848faSopenharmony_ci		}
671f9f848faSopenharmony_ci	}
672f9f848faSopenharmony_ci}
673f9f848faSopenharmony_ci
674f9f848faSopenharmony_ci/*
675f9f848faSopenharmony_ci * There is something wrong with the original function and delete the code;
676f9f848faSopenharmony_ci * If you want to use, you should realize it again.
677f9f848faSopenharmony_ci */
678f9f848faSopenharmony_ciint
679f9f848faSopenharmony_cipbuf_append(struct pbuf *m0, int length, void* cp)
680f9f848faSopenharmony_ci{
681f9f848faSopenharmony_ci	return (0);
682f9f848faSopenharmony_ci}
683f9f848faSopenharmony_ci
684f9f848faSopenharmony_ci
685f9f848faSopenharmony_ci
686f9f848faSopenharmony_cistatic void
687f9f848faSopenharmony_cicdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
688f9f848faSopenharmony_ci{
689f9f848faSopenharmony_ci	struct cdce_softc *sc = (struct cdce_softc *)usbd_xfer_softc(xfer);
690f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
691f9f848faSopenharmony_ci	struct pbuf *m;
692f9f848faSopenharmony_ci	uint32_t crc;
693f9f848faSopenharmony_ci	uint8_t x;
694f9f848faSopenharmony_ci	int actlen, aframes;
695f9f848faSopenharmony_ci
696f9f848faSopenharmony_ci	DPRINTFN(10, "\n");
697f9f848faSopenharmony_ci
698f9f848faSopenharmony_ci	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
699f9f848faSopenharmony_ci
700f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer)) {
701f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
702f9f848faSopenharmony_ci		DPRINTFN(10, "transfer complete: %u bytes in %u frames\n",actlen, aframes);
703f9f848faSopenharmony_ci
704f9f848faSopenharmony_ci		/* free all previous TX buffers */
705f9f848faSopenharmony_ci		cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX);
706f9f848faSopenharmony_ci
707f9f848faSopenharmony_ci		/* FALLTHROUGH */
708f9f848faSopenharmony_ci	case USB_ST_SETUP:
709f9f848faSopenharmony_citr_setup:
710f9f848faSopenharmony_ci		for (x = 0; x != CDCE_FRAMES_MAX; x++) {
711f9f848faSopenharmony_ci			UE_LOCK(ue);
712f9f848faSopenharmony_ci			IF_DEQUEUE(&(ue->ue_txq), m);
713f9f848faSopenharmony_ci			UE_UNLOCK(ue);
714f9f848faSopenharmony_ci			if (m == NULL)
715f9f848faSopenharmony_ci				break;
716f9f848faSopenharmony_ci
717f9f848faSopenharmony_ci			if (sc->sc_flags & CDCE_FLAG_ZAURUS) {
718f9f848faSopenharmony_ci				/*
719f9f848faSopenharmony_ci				 * Zaurus wants a 32-bit CRC appended
720f9f848faSopenharmony_ci				 * to every frame
721f9f848faSopenharmony_ci				 */
722f9f848faSopenharmony_ci
723f9f848faSopenharmony_ci				crc = cdce_m_crc32(m, 0, m->len);
724f9f848faSopenharmony_ci				crc = htole32(crc);
725f9f848faSopenharmony_ci
726f9f848faSopenharmony_ci				if (!pbuf_append(m, 4, (void *)&crc)) {
727f9f848faSopenharmony_ci					free(m);
728f9f848faSopenharmony_ci					continue;
729f9f848faSopenharmony_ci				}
730f9f848faSopenharmony_ci			}
731f9f848faSopenharmony_ci
732f9f848faSopenharmony_ci			sc->sc_tx_buf[x] = m;
733f9f848faSopenharmony_ci			usbd_xfer_set_frame_data(xfer, x, m->payload, m->len);
734f9f848faSopenharmony_ci
735f9f848faSopenharmony_ci			/*
736f9f848faSopenharmony_ci			 * If there's a BPF listener, bounce a copy of
737f9f848faSopenharmony_ci			 * this frame to him:
738f9f848faSopenharmony_ci			 */
739f9f848faSopenharmony_ci		}
740f9f848faSopenharmony_ci		if (x != 0) {
741f9f848faSopenharmony_ci			usbd_xfer_set_frames(xfer, x);
742f9f848faSopenharmony_ci			usbd_transfer_submit(xfer);
743f9f848faSopenharmony_ci		}
744f9f848faSopenharmony_ci		break;
745f9f848faSopenharmony_ci
746f9f848faSopenharmony_ci	default:			/* Error */
747f9f848faSopenharmony_ci		DPRINTFN(11, "transfer error, %s\n",usbd_errstr(error));
748f9f848faSopenharmony_ci		PRINTK("transfer error, %s\n",usbd_errstr(error));
749f9f848faSopenharmony_ci
750f9f848faSopenharmony_ci		/* free all previous TX buffers */
751f9f848faSopenharmony_ci		cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX);
752f9f848faSopenharmony_ci
753f9f848faSopenharmony_ci		if (error != USB_ERR_CANCELLED) {
754f9f848faSopenharmony_ci			/* try to clear stall first */
755f9f848faSopenharmony_ci			usbd_xfer_set_stall(xfer);
756f9f848faSopenharmony_ci			goto tr_setup;
757f9f848faSopenharmony_ci		}
758f9f848faSopenharmony_ci		break;
759f9f848faSopenharmony_ci	}
760f9f848faSopenharmony_ci}
761f9f848faSopenharmony_ci
762f9f848faSopenharmony_cistatic uint32_t
763f9f848faSopenharmony_cicdce_m_crc32(struct pbuf *m, uint32_t src_offset, uint32_t src_len)
764f9f848faSopenharmony_ci{
765f9f848faSopenharmony_ci	uint32_t crc = 0xFFFFFFFF;
766f9f848faSopenharmony_ci
767f9f848faSopenharmony_ci	crc = crc32(crc, m->payload, src_len);
768f9f848faSopenharmony_ci	return (crc ^ 0xFFFFFFFF);
769f9f848faSopenharmony_ci}
770f9f848faSopenharmony_ci
771f9f848faSopenharmony_cistatic void
772f9f848faSopenharmony_cicdce_init(struct usb_ether *ue)
773f9f848faSopenharmony_ci{
774f9f848faSopenharmony_ci	struct cdce_softc *sc = (struct cdce_softc *)uether_getsc(ue);
775f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
776f9f848faSopenharmony_ci	struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)ifp->driver_context;
777f9f848faSopenharmony_ci
778f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
779f9f848faSopenharmony_ci
780f9f848faSopenharmony_ci	CDCE_LOCK_ASSERT(sc, MA_OWNED);
781f9f848faSopenharmony_ci
782f9f848faSopenharmony_ci	drv_sc->state |= IFF_DRV_RUNNING;
783f9f848faSopenharmony_ci
784f9f848faSopenharmony_ci	/* start interrupt transfer */
785f9f848faSopenharmony_ci	usbd_transfer_start(sc->sc_xfer[CDCE_INTR_RX]);
786f9f848faSopenharmony_ci	usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]);
787f9f848faSopenharmony_ci
788f9f848faSopenharmony_ci	/*
789f9f848faSopenharmony_ci	 * Stall data write direction, which depends on USB mode.
790f9f848faSopenharmony_ci	 *
791f9f848faSopenharmony_ci	 * Some USB host stacks (e.g. Mac OS X) don't clears stall
792f9f848faSopenharmony_ci	 * bit as it should, so set it in our host mode only.
793f9f848faSopenharmony_ci	 */
794f9f848faSopenharmony_ci	if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST)
795f9f848faSopenharmony_ci		usbd_xfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]);
796f9f848faSopenharmony_ci
797f9f848faSopenharmony_ci	/* start data transfers */
798f9f848faSopenharmony_ci	cdce_start(ue);
799f9f848faSopenharmony_ci}
800f9f848faSopenharmony_ci
801f9f848faSopenharmony_cistatic void
802f9f848faSopenharmony_cicdce_stop(struct usb_ether *ue)
803f9f848faSopenharmony_ci{
804f9f848faSopenharmony_ci	struct cdce_softc *sc = (struct cdce_softc *)uether_getsc(ue);
805f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
806f9f848faSopenharmony_ci	struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)ifp->driver_context;
807f9f848faSopenharmony_ci
808f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
809f9f848faSopenharmony_ci
810f9f848faSopenharmony_ci	CDCE_LOCK_ASSERT(sc, MA_OWNED);
811f9f848faSopenharmony_ci
812f9f848faSopenharmony_ci	drv_sc->state &= ~IFF_DRV_RUNNING;
813f9f848faSopenharmony_ci
814f9f848faSopenharmony_ci	/*
815f9f848faSopenharmony_ci	 * stop all the transfers, if not already stopped:
816f9f848faSopenharmony_ci	 */
817f9f848faSopenharmony_ci	usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_RX]);
818f9f848faSopenharmony_ci	usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_TX]);
819f9f848faSopenharmony_ci	usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_RX]);
820f9f848faSopenharmony_ci	usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_TX]);
821f9f848faSopenharmony_ci}
822f9f848faSopenharmony_ci
823f9f848faSopenharmony_cistatic void
824f9f848faSopenharmony_cicdce_setmulti(struct usb_ether *ue)
825f9f848faSopenharmony_ci{
826f9f848faSopenharmony_ci	/* no-op */
827f9f848faSopenharmony_ci	return;
828f9f848faSopenharmony_ci}
829f9f848faSopenharmony_ci
830f9f848faSopenharmony_cistatic void
831f9f848faSopenharmony_cicdce_setpromisc(struct usb_ether *ue)
832f9f848faSopenharmony_ci{
833f9f848faSopenharmony_ci	/* no-op */
834f9f848faSopenharmony_ci	return;
835f9f848faSopenharmony_ci}
836f9f848faSopenharmony_ci
837f9f848faSopenharmony_cistatic int
838f9f848faSopenharmony_cicdce_suspend(device_t dev)
839f9f848faSopenharmony_ci{
840f9f848faSopenharmony_ci	device_printf(dev, "Suspending\n");
841f9f848faSopenharmony_ci	return (0);
842f9f848faSopenharmony_ci}
843f9f848faSopenharmony_ci
844f9f848faSopenharmony_cistatic int
845f9f848faSopenharmony_cicdce_resume(device_t dev)
846f9f848faSopenharmony_ci{
847f9f848faSopenharmony_ci	device_printf(dev, "Resuming\n");
848f9f848faSopenharmony_ci	return (0);
849f9f848faSopenharmony_ci}
850f9f848faSopenharmony_ci
851f9f848faSopenharmony_cistatic void
852f9f848faSopenharmony_cicdce_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
853f9f848faSopenharmony_ci{
854f9f848faSopenharmony_ci	struct cdce_softc *sc = (struct cdce_softc *)usbd_xfer_softc(xfer);
855f9f848faSopenharmony_ci	struct pbuf *m;
856f9f848faSopenharmony_ci	uint8_t x;
857f9f848faSopenharmony_ci	int actlen;
858f9f848faSopenharmony_ci	int aframes;
859f9f848faSopenharmony_ci	int len;
860f9f848faSopenharmony_ci
861f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
862f9f848faSopenharmony_ci	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
863f9f848faSopenharmony_ci
864f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer)) {
865f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
866f9f848faSopenharmony_ci
867f9f848faSopenharmony_ci		DPRINTF("received %u bytes in %u frames\n", actlen, aframes);
868f9f848faSopenharmony_ci
869f9f848faSopenharmony_ci		for (x = 0; x != aframes; x++) {
870f9f848faSopenharmony_ci			m = sc->sc_rx_buf[x];
871f9f848faSopenharmony_ci			sc->sc_rx_buf[x] = NULL;
872f9f848faSopenharmony_ci			len = usbd_xfer_frame_len(xfer, x);
873f9f848faSopenharmony_ci
874f9f848faSopenharmony_ci			/* Strip off CRC added by Zaurus, if any */
875f9f848faSopenharmony_ci			if ((sc->sc_flags & CDCE_FLAG_ZAURUS) && len >= 14)
876f9f848faSopenharmony_ci				len -= 4;
877f9f848faSopenharmony_ci
878f9f848faSopenharmony_ci			if (len < (int)sizeof(struct ether_header)) {
879f9f848faSopenharmony_ci				uether_freebuf(m);
880f9f848faSopenharmony_ci				continue;
881f9f848faSopenharmony_ci			}
882f9f848faSopenharmony_ci			/* queue up mbuf */
883f9f848faSopenharmony_ci			(void)uether_rxmbuf(&sc->sc_ue, m, len);
884f9f848faSopenharmony_ci		}
885f9f848faSopenharmony_ci
886f9f848faSopenharmony_ci		/* FALLTHROUGH */
887f9f848faSopenharmony_ci	case USB_ST_SETUP:
888f9f848faSopenharmony_ci		/*
889f9f848faSopenharmony_ci		 * TODO: Implement support for multi frame transfers,
890f9f848faSopenharmony_ci		 * when the USB hardware supports it.
891f9f848faSopenharmony_ci		 */
892f9f848faSopenharmony_ci		for (x = 0; x != 1; x++) { /* why x is alway 0? */
893f9f848faSopenharmony_ci			if (sc->sc_rx_buf[x] == NULL) {
894f9f848faSopenharmony_ci				m = uether_newbuf(MAX_ETH_MSG);
895f9f848faSopenharmony_ci				if (m == NULL)
896f9f848faSopenharmony_ci					goto tr_stall;
897f9f848faSopenharmony_ci				sc->sc_rx_buf[x] = m;
898f9f848faSopenharmony_ci			} else {
899f9f848faSopenharmony_ci				m = sc->sc_rx_buf[x];
900f9f848faSopenharmony_ci			}
901f9f848faSopenharmony_ci
902f9f848faSopenharmony_ci			DPRINTFN(1, "new buffer length %d\n", m->len);
903f9f848faSopenharmony_ci			usbd_xfer_set_frame_data(xfer, x, m->payload, m->len);
904f9f848faSopenharmony_ci		}
905f9f848faSopenharmony_ci		/* set number of frames and start hardware */
906f9f848faSopenharmony_ci		usbd_xfer_set_frames(xfer, x);
907f9f848faSopenharmony_ci		usbd_transfer_submit(xfer);
908f9f848faSopenharmony_ci		/* flush any received frames */
909f9f848faSopenharmony_ci		uether_rxflush(&sc->sc_ue);
910f9f848faSopenharmony_ci		break;
911f9f848faSopenharmony_ci
912f9f848faSopenharmony_ci	default:			/* Error */
913f9f848faSopenharmony_ci		DPRINTF("error = %s\n",usbd_errstr(error));
914f9f848faSopenharmony_ci
915f9f848faSopenharmony_ci		if (error != USB_ERR_CANCELLED) {
916f9f848faSopenharmony_citr_stall:
917f9f848faSopenharmony_ci			/* try to clear stall first */
918f9f848faSopenharmony_ci			usbd_xfer_set_stall(xfer);
919f9f848faSopenharmony_ci			usbd_xfer_set_frames(xfer, 0);
920f9f848faSopenharmony_ci			usbd_transfer_submit(xfer);
921f9f848faSopenharmony_ci			break;
922f9f848faSopenharmony_ci		}
923f9f848faSopenharmony_ci
924f9f848faSopenharmony_ci		/* need to free the RX-mbufs when we are cancelled */
925f9f848faSopenharmony_ci		cdce_free_queue(sc->sc_rx_buf, CDCE_FRAMES_MAX);
926f9f848faSopenharmony_ci		break;
927f9f848faSopenharmony_ci	}
928f9f848faSopenharmony_ci}
929f9f848faSopenharmony_ci
930f9f848faSopenharmony_cistatic void
931f9f848faSopenharmony_cicdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
932f9f848faSopenharmony_ci{
933f9f848faSopenharmony_ci	int actlen;
934f9f848faSopenharmony_ci
935f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
936f9f848faSopenharmony_ci
937f9f848faSopenharmony_ci	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
938f9f848faSopenharmony_ci
939f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer)) {
940f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
941f9f848faSopenharmony_ci
942f9f848faSopenharmony_ci		DPRINTF("cdce_intr_read_callback Received %d bytes\n", actlen);
943f9f848faSopenharmony_ci
944f9f848faSopenharmony_ci		/* TODO: decode some indications */
945f9f848faSopenharmony_ci
946f9f848faSopenharmony_ci		/* FALLTHROUGH */
947f9f848faSopenharmony_ci	case USB_ST_SETUP:
948f9f848faSopenharmony_citr_setup:
949f9f848faSopenharmony_ci		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
950f9f848faSopenharmony_ci		usbd_transfer_submit(xfer);
951f9f848faSopenharmony_ci		break;
952f9f848faSopenharmony_ci
953f9f848faSopenharmony_ci	default:			/* Error */
954f9f848faSopenharmony_ci		if (error != USB_ERR_CANCELLED) {
955f9f848faSopenharmony_ci			/* start clear stall */
956f9f848faSopenharmony_ci			usbd_xfer_set_stall(xfer);
957f9f848faSopenharmony_ci			goto tr_setup;
958f9f848faSopenharmony_ci		}
959f9f848faSopenharmony_ci		break;
960f9f848faSopenharmony_ci	}
961f9f848faSopenharmony_ci}
962f9f848faSopenharmony_ci
963f9f848faSopenharmony_cistatic void
964f9f848faSopenharmony_cicdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error)
965f9f848faSopenharmony_ci{
966f9f848faSopenharmony_ci	struct cdce_softc *sc = usbd_xfer_softc(xfer);
967f9f848faSopenharmony_ci	struct usb_cdc_notification req;
968f9f848faSopenharmony_ci	struct usb_page_cache *pc;
969f9f848faSopenharmony_ci	uint32_t speed;
970f9f848faSopenharmony_ci	int actlen;
971f9f848faSopenharmony_ci
972f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
973f9f848faSopenharmony_ci
974f9f848faSopenharmony_ci	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
975f9f848faSopenharmony_ci
976f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer)) {
977f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
978f9f848faSopenharmony_ci
979f9f848faSopenharmony_ci		DPRINTF("Transferred %d bytes\n", actlen);
980f9f848faSopenharmony_ci
981f9f848faSopenharmony_ci		switch (sc->sc_notify_state) {
982f9f848faSopenharmony_ci		case CDCE_NOTIFY_NETWORK_CONNECTION:
983f9f848faSopenharmony_ci			sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE;
984f9f848faSopenharmony_ci			break;
985f9f848faSopenharmony_ci		case CDCE_NOTIFY_SPEED_CHANGE:
986f9f848faSopenharmony_ci			sc->sc_notify_state = CDCE_NOTIFY_DONE;
987f9f848faSopenharmony_ci			break;
988f9f848faSopenharmony_ci		default:
989f9f848faSopenharmony_ci			break;
990f9f848faSopenharmony_ci		}
991f9f848faSopenharmony_ci		/* FALLTHROUGH */
992f9f848faSopenharmony_ci	case USB_ST_SETUP:
993f9f848faSopenharmony_citr_setup:
994f9f848faSopenharmony_ci		/*
995f9f848faSopenharmony_ci		 * Inform host about connection. Required according to USB CDC
996f9f848faSopenharmony_ci		 * specification and communicating to Mac OS X USB host stack.
997f9f848faSopenharmony_ci		 * Some of the values seems ignored by Mac OS X though.
998f9f848faSopenharmony_ci		 */
999f9f848faSopenharmony_ci		if (sc->sc_notify_state == CDCE_NOTIFY_NETWORK_CONNECTION) {
1000f9f848faSopenharmony_ci			req.bmRequestType = UCDC_NOTIFICATION;
1001f9f848faSopenharmony_ci			req.bNotification = UCDC_N_NETWORK_CONNECTION;
1002f9f848faSopenharmony_ci			req.wIndex[0] = sc->sc_ifaces_index[1];
1003f9f848faSopenharmony_ci			req.wIndex[1] = 0;
1004f9f848faSopenharmony_ci			USETW(req.wValue, 1); /* Connected */
1005f9f848faSopenharmony_ci			USETW(req.wLength, 0);
1006f9f848faSopenharmony_ci
1007f9f848faSopenharmony_ci			pc = usbd_xfer_get_frame(xfer, 0);
1008f9f848faSopenharmony_ci			usbd_copy_in(pc, 0, &req, sizeof(req));
1009f9f848faSopenharmony_ci			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1010f9f848faSopenharmony_ci			usbd_xfer_set_frames(xfer, 1);
1011f9f848faSopenharmony_ci			usbd_transfer_submit(xfer);
1012f9f848faSopenharmony_ci		} else if (sc->sc_notify_state == CDCE_NOTIFY_SPEED_CHANGE) {
1013f9f848faSopenharmony_ci			req.bmRequestType = UCDC_NOTIFICATION;
1014f9f848faSopenharmony_ci			req.bNotification = UCDC_N_CONNECTION_SPEED_CHANGE;
1015f9f848faSopenharmony_ci			req.wIndex[0] = sc->sc_ifaces_index[1];
1016f9f848faSopenharmony_ci			req.wIndex[1] = 0;
1017f9f848faSopenharmony_ci			USETW(req.wValue, 0);
1018f9f848faSopenharmony_ci			USETW(req.wLength, 8);
1019f9f848faSopenharmony_ci
1020f9f848faSopenharmony_ci			/* Peak theoretical bulk trasfer rate in bits/s */
1021f9f848faSopenharmony_ci			if (usbd_get_speed(sc->sc_ue.ue_udev) != USB_SPEED_FULL)
1022f9f848faSopenharmony_ci				speed = (13 * 512 * 8 * 1000 * 8);
1023f9f848faSopenharmony_ci			else
1024f9f848faSopenharmony_ci				speed = (19 * 64 * 1 * 1000 * 8);
1025f9f848faSopenharmony_ci
1026f9f848faSopenharmony_ci			USETDW(req.data + 0, speed); /* Upstream bit rate */
1027f9f848faSopenharmony_ci			USETDW(req.data + 4, speed); /* Downstream bit rate */
1028f9f848faSopenharmony_ci
1029f9f848faSopenharmony_ci			pc = usbd_xfer_get_frame(xfer, 0);
1030f9f848faSopenharmony_ci			usbd_copy_in(pc, 0, &req, sizeof(req));
1031f9f848faSopenharmony_ci			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1032f9f848faSopenharmony_ci			usbd_xfer_set_frames(xfer, 1);
1033f9f848faSopenharmony_ci			usbd_transfer_submit(xfer);
1034f9f848faSopenharmony_ci		}
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_cistatic int
1048f9f848faSopenharmony_cicdce_handle_request(device_t dev,
1049f9f848faSopenharmony_ci    const void *preq, void **pptr, uint16_t *plen,
1050f9f848faSopenharmony_ci    uint16_t offset, uint8_t *pstate)
1051f9f848faSopenharmony_ci{
1052f9f848faSopenharmony_ci	struct cdce_softc *sc = device_get_softc(dev);
1053f9f848faSopenharmony_ci	const struct usb_device_request *req = preq;
1054f9f848faSopenharmony_ci	uint8_t is_complete = *pstate;
1055f9f848faSopenharmony_ci
1056f9f848faSopenharmony_ci	/*
1057f9f848faSopenharmony_ci	 * When Mac OS X resumes after suspending it expects
1058f9f848faSopenharmony_ci	 * to be notified again after this request.
1059f9f848faSopenharmony_ci	 */
1060f9f848faSopenharmony_ci	if (req->bmRequestType == UT_WRITE_CLASS_INTERFACE && \
1061f9f848faSopenharmony_ci	    req->bRequest == UCDC_NCM_SET_ETHERNET_PACKET_FILTER) {
1062f9f848faSopenharmony_ci		if (is_complete == 1) {
1063f9f848faSopenharmony_ci			mtx_lock(&sc->sc_mtx);
1064f9f848faSopenharmony_ci			sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE;
1065f9f848faSopenharmony_ci			usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]);
1066f9f848faSopenharmony_ci			mtx_unlock(&sc->sc_mtx);
1067f9f848faSopenharmony_ci		}
1068f9f848faSopenharmony_ci
1069f9f848faSopenharmony_ci		return (0);
1070f9f848faSopenharmony_ci	}
1071f9f848faSopenharmony_ci
1072f9f848faSopenharmony_ci	return (ENXIO);	 /* use builtin handler */
1073f9f848faSopenharmony_ci}
1074f9f848faSopenharmony_ci
1075f9f848faSopenharmony_ci#if CDCE_HAVE_NCM
1076f9f848faSopenharmony_cistatic void
1077f9f848faSopenharmony_cicdce_ncm_tx_zero(struct usb_page_cache *pc,
1078f9f848faSopenharmony_ci    uint32_t start, uint32_t end)
1079f9f848faSopenharmony_ci{
1080f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
1081f9f848faSopenharmony_ci
1082f9f848faSopenharmony_ci	if (start >= CDCE_NCM_TX_MAXLEN)
1083f9f848faSopenharmony_ci		return;
1084f9f848faSopenharmony_ci	if (end > CDCE_NCM_TX_MAXLEN)
1085f9f848faSopenharmony_ci		end = CDCE_NCM_TX_MAXLEN;
1086f9f848faSopenharmony_ci
1087f9f848faSopenharmony_ci	usbd_frame_zero(pc, start, end - start);
1088f9f848faSopenharmony_ci}
1089f9f848faSopenharmony_ci
1090f9f848faSopenharmony_cistatic uint8_t
1091f9f848faSopenharmony_cicdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index)
1092f9f848faSopenharmony_ci{
1093f9f848faSopenharmony_ci	struct cdce_softc *sc = usbd_xfer_softc(xfer);
1094f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
1095f9f848faSopenharmony_ci	struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, index);
1096f9f848faSopenharmony_ci	struct pbuf *m;
1097f9f848faSopenharmony_ci	uint32_t rem;
1098f9f848faSopenharmony_ci	uint32_t offset;
1099f9f848faSopenharmony_ci	uint32_t last_offset;
1100f9f848faSopenharmony_ci	uint16_t n;
1101f9f848faSopenharmony_ci	uint8_t retval;
1102f9f848faSopenharmony_ci
1103f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
1104f9f848faSopenharmony_ci
1105f9f848faSopenharmony_ci	usbd_xfer_set_frame_offset(xfer, index * CDCE_NCM_TX_MAXLEN, index);
1106f9f848faSopenharmony_ci
1107f9f848faSopenharmony_ci	offset = sizeof(sc->sc_ncm.hdr) +
1108f9f848faSopenharmony_ci	    sizeof(sc->sc_ncm.dpt) + sizeof(sc->sc_ncm.dp);
1109f9f848faSopenharmony_ci
1110f9f848faSopenharmony_ci	/* Store last valid offset before alignment */
1111f9f848faSopenharmony_ci	last_offset = offset;
1112f9f848faSopenharmony_ci
1113f9f848faSopenharmony_ci	/* Align offset */
1114f9f848faSopenharmony_ci	offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder,
1115f9f848faSopenharmony_ci	    offset, sc->sc_ncm.tx_modulus);
1116f9f848faSopenharmony_ci
1117f9f848faSopenharmony_ci	/* Zero pad */
1118f9f848faSopenharmony_ci	cdce_ncm_tx_zero(pc, last_offset, offset);
1119f9f848faSopenharmony_ci
1120f9f848faSopenharmony_ci	/* buffer full */
1121f9f848faSopenharmony_ci	retval = 2;
1122f9f848faSopenharmony_ci
1123f9f848faSopenharmony_ci	for (n = 0; n != sc->sc_ncm.tx_nframe; n++) {
1124f9f848faSopenharmony_ci		/* check if end of transmit buffer is reached */
1125f9f848faSopenharmony_ci
1126f9f848faSopenharmony_ci		if (offset >= sc->sc_ncm.tx_max)
1127f9f848faSopenharmony_ci			break;
1128f9f848faSopenharmony_ci
1129f9f848faSopenharmony_ci		/* compute maximum buffer size */
1130f9f848faSopenharmony_ci
1131f9f848faSopenharmony_ci		rem = sc->sc_ncm.tx_max - offset;
1132f9f848faSopenharmony_ci
1133f9f848faSopenharmony_ci		IF_DEQUEUE(&(ue->ue_txq), m);
1134f9f848faSopenharmony_ci
1135f9f848faSopenharmony_ci		if (m == NULL) {
1136f9f848faSopenharmony_ci			/* buffer not full */
1137f9f848faSopenharmony_ci			retval = 1;
1138f9f848faSopenharmony_ci			break;
1139f9f848faSopenharmony_ci		}
1140f9f848faSopenharmony_ci
1141f9f848faSopenharmony_ci		if (m->len > (int)rem) {
1142f9f848faSopenharmony_ci			if (n == 0) {
1143f9f848faSopenharmony_ci				/* The frame won't fit in our buffer */
1144f9f848faSopenharmony_ci				DPRINTFN(1, "Frame too big to be transmitted!\n");
1145f9f848faSopenharmony_ci				pbuf_free(m);
1146f9f848faSopenharmony_ci				n--;
1147f9f848faSopenharmony_ci				continue;
1148f9f848faSopenharmony_ci			}
1149f9f848faSopenharmony_ci			/* Wait till next buffer becomes ready */
1150f9f848faSopenharmony_ci			IF_PREPEND(&(ue->ue_txq), m);
1151f9f848faSopenharmony_ci			break;
1152f9f848faSopenharmony_ci		}
1153f9f848faSopenharmony_ci		usbd_copy_in(pc, offset, m->payload, m->len);
1154f9f848faSopenharmony_ci
1155f9f848faSopenharmony_ci		USETW(sc->sc_ncm.dp[n].wFrameLength, m->len);
1156f9f848faSopenharmony_ci		USETW(sc->sc_ncm.dp[n].wFrameIndex, offset);
1157f9f848faSopenharmony_ci
1158f9f848faSopenharmony_ci		/* Update offset */
1159f9f848faSopenharmony_ci		offset += m->len;
1160f9f848faSopenharmony_ci
1161f9f848faSopenharmony_ci		/* Store last valid offset before alignment */
1162f9f848faSopenharmony_ci		last_offset = offset;
1163f9f848faSopenharmony_ci
1164f9f848faSopenharmony_ci		/* Align offset */
1165f9f848faSopenharmony_ci		offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder,
1166f9f848faSopenharmony_ci		    offset, sc->sc_ncm.tx_modulus);
1167f9f848faSopenharmony_ci
1168f9f848faSopenharmony_ci		/* Zero pad */
1169f9f848faSopenharmony_ci		cdce_ncm_tx_zero(pc, last_offset, offset);
1170f9f848faSopenharmony_ci
1171f9f848faSopenharmony_ci		/* Free mbuf */
1172f9f848faSopenharmony_ci		pbuf_free(m);
1173f9f848faSopenharmony_ci	}
1174f9f848faSopenharmony_ci
1175f9f848faSopenharmony_ci	if (n == 0)
1176f9f848faSopenharmony_ci		return (0);
1177f9f848faSopenharmony_ci
1178f9f848faSopenharmony_ci	rem = (sizeof(sc->sc_ncm.dpt) + (4 * n) + 4);
1179f9f848faSopenharmony_ci
1180f9f848faSopenharmony_ci	USETW(sc->sc_ncm.dpt.wLength, rem);
1181f9f848faSopenharmony_ci
1182f9f848faSopenharmony_ci	/* zero the rest of the data pointer entries */
1183f9f848faSopenharmony_ci	for (; n != CDCE_NCM_SUBFRAMES_MAX; n++) {
1184f9f848faSopenharmony_ci		USETW(sc->sc_ncm.dp[n].wFrameLength, 0);
1185f9f848faSopenharmony_ci		USETW(sc->sc_ncm.dp[n].wFrameIndex, 0);
1186f9f848faSopenharmony_ci	}
1187f9f848faSopenharmony_ci
1188f9f848faSopenharmony_ci	offset = last_offset;
1189f9f848faSopenharmony_ci
1190f9f848faSopenharmony_ci	/* Align offset */
1191f9f848faSopenharmony_ci	offset = CDCE_NCM_ALIGN(0, offset, CDCE_NCM_TX_MINLEN);
1192f9f848faSopenharmony_ci
1193f9f848faSopenharmony_ci	/* Optimise, save bandwidth and force short termination */
1194f9f848faSopenharmony_ci	if (offset >= sc->sc_ncm.tx_max)
1195f9f848faSopenharmony_ci		offset = sc->sc_ncm.tx_max;
1196f9f848faSopenharmony_ci	else
1197f9f848faSopenharmony_ci		offset ++;
1198f9f848faSopenharmony_ci
1199f9f848faSopenharmony_ci	/* Zero pad */
1200f9f848faSopenharmony_ci	cdce_ncm_tx_zero(pc, last_offset, offset);
1201f9f848faSopenharmony_ci
1202f9f848faSopenharmony_ci	/* set frame length */
1203f9f848faSopenharmony_ci	usbd_xfer_set_frame_len(xfer, index, offset);
1204f9f848faSopenharmony_ci
1205f9f848faSopenharmony_ci	/* Fill out 16-bit header */
1206f9f848faSopenharmony_ci	sc->sc_ncm.hdr.dwSignature[0] = 'N';
1207f9f848faSopenharmony_ci	sc->sc_ncm.hdr.dwSignature[1] = 'C';
1208f9f848faSopenharmony_ci	sc->sc_ncm.hdr.dwSignature[2] = 'M';
1209f9f848faSopenharmony_ci	sc->sc_ncm.hdr.dwSignature[3] = 'H';
1210f9f848faSopenharmony_ci	USETW(sc->sc_ncm.hdr.wHeaderLength, sizeof(sc->sc_ncm.hdr));
1211f9f848faSopenharmony_ci	USETW(sc->sc_ncm.hdr.wBlockLength, offset);
1212f9f848faSopenharmony_ci	USETW(sc->sc_ncm.hdr.wSequence, sc->sc_ncm.tx_seq);
1213f9f848faSopenharmony_ci	USETW(sc->sc_ncm.hdr.wDptIndex, sizeof(sc->sc_ncm.hdr));
1214f9f848faSopenharmony_ci
1215f9f848faSopenharmony_ci	sc->sc_ncm.tx_seq++;
1216f9f848faSopenharmony_ci
1217f9f848faSopenharmony_ci	/* Fill out 16-bit frame table header */
1218f9f848faSopenharmony_ci	sc->sc_ncm.dpt.dwSignature[0] = 'N';
1219f9f848faSopenharmony_ci	sc->sc_ncm.dpt.dwSignature[1] = 'C';
1220f9f848faSopenharmony_ci	sc->sc_ncm.dpt.dwSignature[2] = 'M';
1221f9f848faSopenharmony_ci	sc->sc_ncm.dpt.dwSignature[3] = '0';
1222f9f848faSopenharmony_ci	USETW(sc->sc_ncm.dpt.wNextNdpIndex, 0);		/* reserved */
1223f9f848faSopenharmony_ci
1224f9f848faSopenharmony_ci	usbd_copy_in(pc, 0, &(sc->sc_ncm.hdr), sizeof(sc->sc_ncm.hdr));
1225f9f848faSopenharmony_ci	usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr), &(sc->sc_ncm.dpt),
1226f9f848faSopenharmony_ci	    sizeof(sc->sc_ncm.dpt));
1227f9f848faSopenharmony_ci	usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt),
1228f9f848faSopenharmony_ci	    &(sc->sc_ncm.dp), sizeof(sc->sc_ncm.dp));
1229f9f848faSopenharmony_ci	return (retval);
1230f9f848faSopenharmony_ci}
1231f9f848faSopenharmony_ci
1232f9f848faSopenharmony_cistatic void
1233f9f848faSopenharmony_cicdce_ncm_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
1234f9f848faSopenharmony_ci{
1235f9f848faSopenharmony_ci	uint16_t x;
1236f9f848faSopenharmony_ci	uint8_t temp;
1237f9f848faSopenharmony_ci	int actlen;
1238f9f848faSopenharmony_ci	int aframes;
1239f9f848faSopenharmony_ci
1240f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
1241f9f848faSopenharmony_ci
1242f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer)) {
1243f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
1244f9f848faSopenharmony_ci
1245f9f848faSopenharmony_ci		usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
1246f9f848faSopenharmony_ci
1247f9f848faSopenharmony_ci		DPRINTFN(10, "transfer complete: "
1248f9f848faSopenharmony_ci			"%u bytes in %u frames\n", actlen, aframes);
1249f9f848faSopenharmony_ci
1250f9f848faSopenharmony_ci	case USB_ST_SETUP:
1251f9f848faSopenharmony_ci		for (x = 0; x != CDCE_NCM_TX_FRAMES_MAX; x++) {
1252f9f848faSopenharmony_ci			temp = cdce_ncm_fill_tx_frames(xfer, x);
1253f9f848faSopenharmony_ci			if (temp == 0)
1254f9f848faSopenharmony_ci				break;
1255f9f848faSopenharmony_ci			if (temp == 1) {
1256f9f848faSopenharmony_ci				x++;
1257f9f848faSopenharmony_ci				break;
1258f9f848faSopenharmony_ci			}
1259f9f848faSopenharmony_ci		}
1260f9f848faSopenharmony_ci
1261f9f848faSopenharmony_ci		if (x != 0) {
1262f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG
1263f9f848faSopenharmony_ci			usbd_xfer_set_interval(xfer, cdce_tx_interval);
1264f9f848faSopenharmony_ci#endif
1265f9f848faSopenharmony_ci			usbd_xfer_set_frames(xfer, x);
1266f9f848faSopenharmony_ci			usbd_transfer_submit(xfer);
1267f9f848faSopenharmony_ci		}
1268f9f848faSopenharmony_ci		break;
1269f9f848faSopenharmony_ci
1270f9f848faSopenharmony_ci	default:			/* Error */
1271f9f848faSopenharmony_ci		DPRINTFN(10, "Transfer error: %s\n",
1272f9f848faSopenharmony_ci		    usbd_errstr(error));
1273f9f848faSopenharmony_ci
1274f9f848faSopenharmony_ci		if (error != USB_ERR_CANCELLED) {
1275f9f848faSopenharmony_ci			/* try to clear stall first */
1276f9f848faSopenharmony_ci			usbd_xfer_set_stall(xfer);
1277f9f848faSopenharmony_ci			usbd_xfer_set_frames(xfer, 0);
1278f9f848faSopenharmony_ci			usbd_transfer_submit(xfer);
1279f9f848faSopenharmony_ci		}
1280f9f848faSopenharmony_ci		break;
1281f9f848faSopenharmony_ci	}
1282f9f848faSopenharmony_ci}
1283f9f848faSopenharmony_ci
1284f9f848faSopenharmony_cistatic void
1285f9f848faSopenharmony_cicdce_ncm_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
1286f9f848faSopenharmony_ci{
1287f9f848faSopenharmony_ci	struct cdce_softc *sc = usbd_xfer_softc(xfer);
1288f9f848faSopenharmony_ci	struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0);
1289f9f848faSopenharmony_ci	struct pbuf *m;
1290f9f848faSopenharmony_ci	int sumdata;
1291f9f848faSopenharmony_ci	int sumlen;
1292f9f848faSopenharmony_ci	int actlen;
1293f9f848faSopenharmony_ci	int aframes;
1294f9f848faSopenharmony_ci	int temp;
1295f9f848faSopenharmony_ci	int nframes;
1296f9f848faSopenharmony_ci	int x;
1297f9f848faSopenharmony_ci	int offset;
1298f9f848faSopenharmony_ci
1299f9f848faSopenharmony_ci	DPRINTFN(1, "\n");
1300f9f848faSopenharmony_ci
1301f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer)) {
1302f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
1303f9f848faSopenharmony_ci
1304f9f848faSopenharmony_ci		usbd_xfer_status(xfer, &actlen, &sumlen, &aframes, NULL);
1305f9f848faSopenharmony_ci
1306f9f848faSopenharmony_ci		DPRINTFN(1, "received %u bytes in %u frames\n",
1307f9f848faSopenharmony_ci		    actlen, aframes);
1308f9f848faSopenharmony_ci
1309f9f848faSopenharmony_ci		if (actlen < (int)(sizeof(sc->sc_ncm.hdr) +
1310f9f848faSopenharmony_ci		    sizeof(sc->sc_ncm.dpt))) {
1311f9f848faSopenharmony_ci			DPRINTFN(1, "frame too short\n");
1312f9f848faSopenharmony_ci			goto tr_setup;
1313f9f848faSopenharmony_ci		}
1314f9f848faSopenharmony_ci		usbd_copy_out(pc, 0, &(sc->sc_ncm.hdr),
1315f9f848faSopenharmony_ci		    sizeof(sc->sc_ncm.hdr));
1316f9f848faSopenharmony_ci
1317f9f848faSopenharmony_ci		if ((sc->sc_ncm.hdr.dwSignature[0] != 'N') ||
1318f9f848faSopenharmony_ci		    (sc->sc_ncm.hdr.dwSignature[1] != 'C') ||
1319f9f848faSopenharmony_ci		    (sc->sc_ncm.hdr.dwSignature[2] != 'M') ||
1320f9f848faSopenharmony_ci		    (sc->sc_ncm.hdr.dwSignature[3] != 'H')) {
1321f9f848faSopenharmony_ci			DPRINTFN(1, "invalid HDR signature: "
1322f9f848faSopenharmony_ci			    "0x%02x:0x%02x:0x%02x:0x%02x\n",
1323f9f848faSopenharmony_ci			    sc->sc_ncm.hdr.dwSignature[0],
1324f9f848faSopenharmony_ci			    sc->sc_ncm.hdr.dwSignature[1],
1325f9f848faSopenharmony_ci			    sc->sc_ncm.hdr.dwSignature[2],
1326f9f848faSopenharmony_ci			    sc->sc_ncm.hdr.dwSignature[3]);
1327f9f848faSopenharmony_ci			goto tr_stall;
1328f9f848faSopenharmony_ci		}
1329f9f848faSopenharmony_ci		temp = UGETW(sc->sc_ncm.hdr.wBlockLength);
1330f9f848faSopenharmony_ci		if (temp > sumlen) {
1331f9f848faSopenharmony_ci			DPRINTFN(1, "unsupported block length %u/%u\n",
1332f9f848faSopenharmony_ci			    temp, sumlen);
1333f9f848faSopenharmony_ci			goto tr_stall;
1334f9f848faSopenharmony_ci		}
1335f9f848faSopenharmony_ci		temp = UGETW(sc->sc_ncm.hdr.wDptIndex);
1336f9f848faSopenharmony_ci		if ((int)(temp + sizeof(sc->sc_ncm.dpt)) > actlen) {
1337f9f848faSopenharmony_ci			DPRINTFN(1, "invalid DPT index: 0x%04x\n", temp);
1338f9f848faSopenharmony_ci			goto tr_stall;
1339f9f848faSopenharmony_ci		}
1340f9f848faSopenharmony_ci		usbd_copy_out(pc, temp, &(sc->sc_ncm.dpt),
1341f9f848faSopenharmony_ci		    sizeof(sc->sc_ncm.dpt));
1342f9f848faSopenharmony_ci
1343f9f848faSopenharmony_ci		if ((sc->sc_ncm.dpt.dwSignature[0] != 'N') ||
1344f9f848faSopenharmony_ci		    (sc->sc_ncm.dpt.dwSignature[1] != 'C') ||
1345f9f848faSopenharmony_ci		    (sc->sc_ncm.dpt.dwSignature[2] != 'M') ||
1346f9f848faSopenharmony_ci		    (sc->sc_ncm.dpt.dwSignature[3] != '0')) {
1347f9f848faSopenharmony_ci			DPRINTFN(1, "invalid DPT signature"
1348f9f848faSopenharmony_ci			    "0x%02x:0x%02x:0x%02x:0x%02x\n",
1349f9f848faSopenharmony_ci			    sc->sc_ncm.dpt.dwSignature[0],
1350f9f848faSopenharmony_ci			    sc->sc_ncm.dpt.dwSignature[1],
1351f9f848faSopenharmony_ci			    sc->sc_ncm.dpt.dwSignature[2],
1352f9f848faSopenharmony_ci			    sc->sc_ncm.dpt.dwSignature[3]);
1353f9f848faSopenharmony_ci			goto tr_stall;
1354f9f848faSopenharmony_ci		}
1355f9f848faSopenharmony_ci		nframes = UGETW(sc->sc_ncm.dpt.wLength) / 4;
1356f9f848faSopenharmony_ci
1357f9f848faSopenharmony_ci		/* Subtract size of header and last zero padded entry */
1358f9f848faSopenharmony_ci		if (nframes >= (2 + 1))
1359f9f848faSopenharmony_ci			nframes -= (2 + 1);
1360f9f848faSopenharmony_ci		else
1361f9f848faSopenharmony_ci			nframes = 0;
1362f9f848faSopenharmony_ci
1363f9f848faSopenharmony_ci		DPRINTFN(1, "nframes = %u\n", nframes);
1364f9f848faSopenharmony_ci
1365f9f848faSopenharmony_ci		temp += sizeof(sc->sc_ncm.dpt);
1366f9f848faSopenharmony_ci
1367f9f848faSopenharmony_ci		if ((temp + (4 * nframes)) > actlen)
1368f9f848faSopenharmony_ci			goto tr_stall;
1369f9f848faSopenharmony_ci
1370f9f848faSopenharmony_ci		if (nframes > CDCE_NCM_SUBFRAMES_MAX) {
1371f9f848faSopenharmony_ci			DPRINTFN(1, "Truncating number of frames from %u to %u\n",
1372f9f848faSopenharmony_ci			    nframes, CDCE_NCM_SUBFRAMES_MAX);
1373f9f848faSopenharmony_ci			nframes = CDCE_NCM_SUBFRAMES_MAX;
1374f9f848faSopenharmony_ci		}
1375f9f848faSopenharmony_ci		usbd_copy_out(pc, temp, &(sc->sc_ncm.dp), (4 * nframes));
1376f9f848faSopenharmony_ci
1377f9f848faSopenharmony_ci		sumdata = 0;
1378f9f848faSopenharmony_ci
1379f9f848faSopenharmony_ci		for (x = 0; x != nframes; x++) {
1380f9f848faSopenharmony_ci
1381f9f848faSopenharmony_ci			offset = UGETW(sc->sc_ncm.dp[x].wFrameIndex);
1382f9f848faSopenharmony_ci			temp = UGETW(sc->sc_ncm.dp[x].wFrameLength);
1383f9f848faSopenharmony_ci
1384f9f848faSopenharmony_ci			if ((offset == 0) ||
1385f9f848faSopenharmony_ci			    (temp < (int)sizeof(struct ether_header)) ||
1386f9f848faSopenharmony_ci			    (temp > (MCLBYTES - ETHER_ALIGN))) {
1387f9f848faSopenharmony_ci				DPRINTFN(1, "NULL frame detected at %d\n", x);
1388f9f848faSopenharmony_ci				m = NULL;
1389f9f848faSopenharmony_ci				/* silently ignore this frame */
1390f9f848faSopenharmony_ci				continue;
1391f9f848faSopenharmony_ci			} else if ((offset + temp) > actlen) {
1392f9f848faSopenharmony_ci				DPRINTFN(1, "invalid frame "
1393f9f848faSopenharmony_ci				    "detected at %d\n", x);
1394f9f848faSopenharmony_ci				m = NULL;
1395f9f848faSopenharmony_ci				/* silently ignore this frame */
1396f9f848faSopenharmony_ci				continue;
1397f9f848faSopenharmony_ci			} else {
1398f9f848faSopenharmony_ci				/* if the tmep here is fragmentary,you could do deallocation */
1399f9f848faSopenharmony_ci				m = pbuf_alloc(PBUF_RAW, temp+ETH_PAD_SIZE, PBUF_RAM);
1400f9f848faSopenharmony_ci			}
1401f9f848faSopenharmony_ci
1402f9f848faSopenharmony_ci			DPRINTFN(16, "frame %u, offset = %u, length = %u \n",
1403f9f848faSopenharmony_ci			    x, offset, temp);
1404f9f848faSopenharmony_ci
1405f9f848faSopenharmony_ci			/* check if we have a buffer */
1406f9f848faSopenharmony_ci			if (m) {
1407f9f848faSopenharmony_ci				#if ETH_PAD_SIZE
1408f9f848faSopenharmony_ci					pbuf_header(m, -ETH_PAD_SIZE); /* drop the padding word */
1409f9f848faSopenharmony_ci				#endif
1410f9f848faSopenharmony_ci
1411f9f848faSopenharmony_ci				usbd_copy_out(pc, offset, m->payload, temp);
1412f9f848faSopenharmony_ci
1413f9f848faSopenharmony_ci				#if ETH_PAD_SIZE
1414f9f848faSopenharmony_ci					pbuf_header(m, ETH_PAD_SIZE); /* drop the padding word */
1415f9f848faSopenharmony_ci				#endif
1416f9f848faSopenharmony_ci
1417f9f848faSopenharmony_ci				/* enqueue */
1418f9f848faSopenharmony_ci				uether_rxmbuf(&sc->sc_ue, m, temp);
1419f9f848faSopenharmony_ci
1420f9f848faSopenharmony_ci				sumdata += temp;
1421f9f848faSopenharmony_ci			}
1422f9f848faSopenharmony_ci		}
1423f9f848faSopenharmony_ci
1424f9f848faSopenharmony_ci		DPRINTFN(1, "Efficiency: %u/%u bytes\n", sumdata, actlen);
1425f9f848faSopenharmony_ci
1426f9f848faSopenharmony_ci	case USB_ST_SETUP:
1427f9f848faSopenharmony_citr_setup:
1428f9f848faSopenharmony_ci		usbd_xfer_set_frame_len(xfer, 0, sc->sc_ncm.rx_max);
1429f9f848faSopenharmony_ci		usbd_xfer_set_frames(xfer, 1);
1430f9f848faSopenharmony_ci		usbd_transfer_submit(xfer);
1431f9f848faSopenharmony_ci		uether_rxflush(&sc->sc_ue);	/* must be last */
1432f9f848faSopenharmony_ci		break;
1433f9f848faSopenharmony_ci
1434f9f848faSopenharmony_ci	default:			/* Error */
1435f9f848faSopenharmony_ci		DPRINTFN(1, "error = %s\n",
1436f9f848faSopenharmony_ci		    usbd_errstr(error));
1437f9f848faSopenharmony_ci
1438f9f848faSopenharmony_ci		if (error != USB_ERR_CANCELLED) {
1439f9f848faSopenharmony_citr_stall:
1440f9f848faSopenharmony_ci			/* try to clear stall first */
1441f9f848faSopenharmony_ci			usbd_xfer_set_stall(xfer);
1442f9f848faSopenharmony_ci			usbd_xfer_set_frames(xfer, 0);
1443f9f848faSopenharmony_ci			usbd_transfer_submit(xfer);
1444f9f848faSopenharmony_ci		}
1445f9f848faSopenharmony_ci		break;
1446f9f848faSopenharmony_ci	}
1447f9f848faSopenharmony_ci}
1448f9f848faSopenharmony_ci#endif
1449f9f848faSopenharmony_ci
1450f9f848faSopenharmony_ci#undef USB_DEBUG_VAR
1451