if_cdce.c revision 246128
1301771Simp/*	$NetBSD: if_cdce.c,v 1.4 2004/10/24 12:50:54 augustss Exp $ */
2301771Simp
3301771Simp/*-
4301771Simp * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com>
5301771Simp * Copyright (c) 2003-2005 Craig Boston
6301771Simp * Copyright (c) 2004 Daniel Hartmeier
7301771Simp * Copyright (c) 2009 Hans Petter Selasky
8301771Simp * All rights reserved.
9301771Simp *
10301771Simp * Redistribution and use in source and binary forms, with or without
11301771Simp * modification, are permitted provided that the following conditions
12301771Simp * are met:
13301771Simp * 1. Redistributions of source code must retain the above copyright
14301771Simp *    notice, this list of conditions and the following disclaimer.
15301771Simp * 2. Redistributions in binary form must reproduce the above copyright
16301771Simp *    notice, this list of conditions and the following disclaimer in the
17301771Simp *    documentation and/or other materials provided with the distribution.
18301771Simp * 3. All advertising materials mentioning features or use of this software
19301771Simp *    must display the following acknowledgement:
20301771Simp *	This product includes software developed by Bill Paul.
21301771Simp * 4. Neither the name of the author nor the names of any co-contributors
22301771Simp *    may be used to endorse or promote products derived from this software
23301771Simp *    without specific prior written permission.
24301771Simp *
25301771Simp * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
26301771Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27301771Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28301771Simp * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR
29301771Simp * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30301771Simp * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31301771Simp * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
32301771Simp * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33301771Simp * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34301771Simp * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35301771Simp * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36301771Simp */
37301771Simp
38301771Simp/*
39301771Simp * USB Communication Device Class (Ethernet Networking Control Model)
40301771Simp * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
41301771Simp */
42301771Simp
43301771Simp/*
44301771Simp * USB Network Control Model (NCM)
45301771Simp * http://www.usb.org/developers/devclass_docs/NCM10.zip
46301771Simp */
47301771Simp
48301771Simp#include <sys/cdefs.h>
49301771Simp__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_cdce.c 246128 2013-01-30 18:01:20Z sbz $");
50301771Simp
51301771Simp#include <sys/stdint.h>
52301771Simp#include <sys/stddef.h>
53301771Simp#include <sys/param.h>
54301771Simp#include <sys/queue.h>
55301771Simp#include <sys/types.h>
56301771Simp#include <sys/systm.h>
57301771Simp#include <sys/kernel.h>
58301771Simp#include <sys/bus.h>
59301771Simp#include <sys/module.h>
60301771Simp#include <sys/lock.h>
61301771Simp#include <sys/mutex.h>
62301771Simp#include <sys/condvar.h>
63301771Simp#include <sys/sysctl.h>
64301771Simp#include <sys/sx.h>
65301771Simp#include <sys/unistd.h>
66301771Simp#include <sys/callout.h>
67301771Simp#include <sys/malloc.h>
68301771Simp#include <sys/priv.h>
69301771Simp
70301771Simp#include <dev/usb/usb.h>
71301771Simp#include <dev/usb/usbdi.h>
72301771Simp#include <dev/usb/usbdi_util.h>
73301771Simp#include <dev/usb/usb_cdc.h>
74301771Simp#include "usbdevs.h"
75301771Simp
76301771Simp#define	USB_DEBUG_VAR cdce_debug
77301771Simp#include <dev/usb/usb_debug.h>
78301771Simp#include <dev/usb/usb_process.h>
79301771Simp#include "usb_if.h"
80301771Simp
81301771Simp#include <dev/usb/net/usb_ethernet.h>
82301771Simp#include <dev/usb/net/if_cdcereg.h>
83301771Simp
84301771Simpstatic device_probe_t cdce_probe;
85301771Simpstatic device_attach_t cdce_attach;
86301771Simpstatic device_detach_t cdce_detach;
87301771Simpstatic device_suspend_t cdce_suspend;
88301771Simpstatic device_resume_t cdce_resume;
89301771Simpstatic usb_handle_request_t cdce_handle_request;
90301771Simp
91301771Simpstatic usb_callback_t cdce_bulk_write_callback;
92301771Simpstatic usb_callback_t cdce_bulk_read_callback;
93301771Simpstatic usb_callback_t cdce_intr_read_callback;
94301771Simpstatic usb_callback_t cdce_intr_write_callback;
95301771Simp
96301771Simp#if CDCE_HAVE_NCM
97301771Simpstatic usb_callback_t cdce_ncm_bulk_write_callback;
98301771Simpstatic usb_callback_t cdce_ncm_bulk_read_callback;
99301771Simp#endif
100301771Simp
101301771Simpstatic uether_fn_t cdce_attach_post;
102301771Simpstatic uether_fn_t cdce_init;
103301771Simpstatic uether_fn_t cdce_stop;
104301771Simpstatic uether_fn_t cdce_start;
105301771Simpstatic uether_fn_t cdce_setmulti;
106301771Simpstatic uether_fn_t cdce_setpromisc;
107301771Simp
108301771Simpstatic uint32_t	cdce_m_crc32(struct mbuf *, uint32_t, uint32_t);
109301771Simp
110301771Simp#ifdef USB_DEBUG
111301771Simpstatic int cdce_debug = 0;
112301771Simpstatic int cdce_tx_interval = 0;
113301771Simp
114301771Simpstatic SYSCTL_NODE(_hw_usb, OID_AUTO, cdce, CTLFLAG_RW, 0, "USB CDC-Ethernet");
115301771SimpSYSCTL_INT(_hw_usb_cdce, OID_AUTO, debug, CTLFLAG_RW, &cdce_debug, 0,
116301771Simp    "Debug level");
117301771SimpSYSCTL_INT(_hw_usb_cdce, OID_AUTO, interval, CTLFLAG_RW, &cdce_tx_interval, 0,
118301771Simp    "NCM transmit interval in ms");
119301771Simp#endif
120301771Simp
121301771Simpstatic const struct usb_config cdce_config[CDCE_N_TRANSFER] = {
122301771Simp
123301771Simp	[CDCE_BULK_RX] = {
124301771Simp		.type = UE_BULK,
125301771Simp		.endpoint = UE_ADDR_ANY,
126301771Simp		.direction = UE_DIR_RX,
127301771Simp		.if_index = 0,
128301771Simp		.frames = CDCE_FRAMES_MAX,
129301771Simp		.bufsize = (CDCE_FRAMES_MAX * MCLBYTES),
130301771Simp		.flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,},
131301771Simp		.callback = cdce_bulk_read_callback,
132301771Simp		.timeout = 0,	/* no timeout */
133301771Simp		.usb_mode = USB_MODE_DUAL,	/* both modes */
134301771Simp	},
135301771Simp
136301771Simp	[CDCE_BULK_TX] = {
137301771Simp		.type = UE_BULK,
138301771Simp		.endpoint = UE_ADDR_ANY,
139301771Simp		.direction = UE_DIR_TX,
140301771Simp		.if_index = 0,
141301771Simp		.frames = CDCE_FRAMES_MAX,
142301771Simp		.bufsize = (CDCE_FRAMES_MAX * MCLBYTES),
143301771Simp		.flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,},
144301771Simp		.callback = cdce_bulk_write_callback,
145301771Simp		.timeout = 10000,	/* 10 seconds */
146301771Simp		.usb_mode = USB_MODE_DUAL,	/* both modes */
147301771Simp	},
148301771Simp
149301771Simp	[CDCE_INTR_RX] = {
150301771Simp		.type = UE_INTERRUPT,
151301771Simp		.endpoint = UE_ADDR_ANY,
152301771Simp		.direction = UE_DIR_RX,
153301771Simp		.if_index = 1,
154301771Simp		.bufsize = CDCE_IND_SIZE_MAX,
155301771Simp		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,},
156301771Simp		.callback = cdce_intr_read_callback,
157301771Simp		.timeout = 0,
158301771Simp		.usb_mode = USB_MODE_HOST,
159301771Simp	},
160301771Simp
161301771Simp	[CDCE_INTR_TX] = {
162301771Simp		.type = UE_INTERRUPT,
163301771Simp		.endpoint = UE_ADDR_ANY,
164301771Simp		.direction = UE_DIR_TX,
165301771Simp		.if_index = 1,
166301771Simp		.bufsize = CDCE_IND_SIZE_MAX,
167301771Simp		.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
168301771Simp		.callback = cdce_intr_write_callback,
169301771Simp		.timeout = 10000,	/* 10 seconds */
170301771Simp		.usb_mode = USB_MODE_DEVICE,
171301771Simp	},
172301771Simp};
173301771Simp
174301771Simp#if CDCE_HAVE_NCM
175301771Simpstatic const struct usb_config cdce_ncm_config[CDCE_N_TRANSFER] = {
176301771Simp
177301771Simp	[CDCE_BULK_RX] = {
178301771Simp		.type = UE_BULK,
179301771Simp		.endpoint = UE_ADDR_ANY,
180301771Simp		.direction = UE_DIR_RX,
181301771Simp		.if_index = 0,
182301771Simp		.frames = CDCE_NCM_RX_FRAMES_MAX,
183301771Simp		.bufsize = (CDCE_NCM_RX_FRAMES_MAX * CDCE_NCM_RX_MAXLEN),
184301771Simp		.flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,},
185301771Simp		.callback = cdce_ncm_bulk_read_callback,
186301771Simp		.timeout = 0,	/* no timeout */
187301771Simp		.usb_mode = USB_MODE_DUAL,	/* both modes */
188301771Simp	},
189301771Simp
190301771Simp	[CDCE_BULK_TX] = {
191301771Simp		.type = UE_BULK,
192301771Simp		.endpoint = UE_ADDR_ANY,
193301771Simp		.direction = UE_DIR_TX,
194301771Simp		.if_index = 0,
195301771Simp		.frames = CDCE_NCM_TX_FRAMES_MAX,
196301771Simp		.bufsize = (CDCE_NCM_TX_FRAMES_MAX * CDCE_NCM_TX_MAXLEN),
197301771Simp		.flags = {.pipe_bof = 1,},
198301771Simp		.callback = cdce_ncm_bulk_write_callback,
199301771Simp		.timeout = 10000,	/* 10 seconds */
200301771Simp		.usb_mode = USB_MODE_DUAL,	/* both modes */
201301771Simp	},
202301771Simp
203301771Simp	[CDCE_INTR_RX] = {
204301771Simp		.type = UE_INTERRUPT,
205301771Simp		.endpoint = UE_ADDR_ANY,
206301771Simp		.direction = UE_DIR_RX,
207301771Simp		.if_index = 1,
208301771Simp		.bufsize = CDCE_IND_SIZE_MAX,
209301771Simp		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,},
210301771Simp		.callback = cdce_intr_read_callback,
211301771Simp		.timeout = 0,
212301771Simp		.usb_mode = USB_MODE_HOST,
213301771Simp	},
214301771Simp
215301771Simp	[CDCE_INTR_TX] = {
216301771Simp		.type = UE_INTERRUPT,
217301771Simp		.endpoint = UE_ADDR_ANY,
218301771Simp		.direction = UE_DIR_TX,
219301771Simp		.if_index = 1,
220301771Simp		.bufsize = CDCE_IND_SIZE_MAX,
221301771Simp		.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
222301771Simp		.callback = cdce_intr_write_callback,
223301771Simp		.timeout = 10000,	/* 10 seconds */
224301771Simp		.usb_mode = USB_MODE_DEVICE,
225301771Simp	},
226301771Simp};
227301771Simp#endif
228301771Simp
229301771Simpstatic device_method_t cdce_methods[] = {
230301771Simp	/* USB interface */
231301771Simp	DEVMETHOD(usb_handle_request, cdce_handle_request),
232301771Simp
233301771Simp	/* Device interface */
234301771Simp	DEVMETHOD(device_probe, cdce_probe),
235301771Simp	DEVMETHOD(device_attach, cdce_attach),
236301771Simp	DEVMETHOD(device_detach, cdce_detach),
237301771Simp	DEVMETHOD(device_suspend, cdce_suspend),
238301771Simp	DEVMETHOD(device_resume, cdce_resume),
239301771Simp
240301771Simp	DEVMETHOD_END
241301771Simp};
242301771Simp
243301771Simpstatic driver_t cdce_driver = {
244301771Simp	.name = "cdce",
245301771Simp	.methods = cdce_methods,
246301771Simp	.size = sizeof(struct cdce_softc),
247301771Simp};
248301771Simp
249301771Simpstatic devclass_t cdce_devclass;
250301771Simp
251301771SimpDRIVER_MODULE(cdce, uhub, cdce_driver, cdce_devclass, NULL, 0);
252301771SimpMODULE_VERSION(cdce, 1);
253301771SimpMODULE_DEPEND(cdce, uether, 1, 1, 1);
254301771SimpMODULE_DEPEND(cdce, usb, 1, 1, 1);
255301771SimpMODULE_DEPEND(cdce, ether, 1, 1, 1);
256301771Simp
257301771Simpstatic const struct usb_ether_methods cdce_ue_methods = {
258301771Simp	.ue_attach_post = cdce_attach_post,
259301771Simp	.ue_start = cdce_start,
260301771Simp	.ue_init = cdce_init,
261301771Simp	.ue_stop = cdce_stop,
262301771Simp	.ue_setmulti = cdce_setmulti,
263301771Simp	.ue_setpromisc = cdce_setpromisc,
264301771Simp};
265301771Simp
266301771Simpstatic const STRUCT_USB_HOST_ID cdce_host_devs[] = {
267301771Simp	{USB_VPI(USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632, CDCE_FLAG_NO_UNION)},
268301771Simp	{USB_VPI(USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250, CDCE_FLAG_NO_UNION)},
269301771Simp	{USB_VPI(USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX, CDCE_FLAG_NO_UNION)},
270301771Simp	{USB_VPI(USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00, CDCE_FLAG_NO_UNION)},
271301771Simp	{USB_VPI(USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)},
272301771Simp	{USB_VPI(USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)},
273301771Simp	{USB_VPI(USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_ETHERNETGADGET, CDCE_FLAG_NO_UNION)},
274301771Simp	{USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501, CDCE_FLAG_NO_UNION)},
275301771Simp	{USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500, CDCE_FLAG_ZAURUS)},
276301771Simp	{USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)},
277301771Simp	{USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLA300, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)},
278301771Simp	{USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC700, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)},
279301771Simp	{USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC750, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)},
280301771Simp};
281301771Simp
282301771Simpstatic const STRUCT_USB_DUAL_ID cdce_dual_devs[] = {
283301771Simp	{USB_IF_CSI(UICLASS_CDC, UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0)},
284301771Simp	{USB_IF_CSI(UICLASS_CDC, UISUBCLASS_MOBILE_DIRECT_LINE_MODEL, 0)},
285301771Simp	{USB_IF_CSI(UICLASS_CDC, UISUBCLASS_NETWORK_CONTROL_MODEL, 0)},
286301771Simp};
287301771Simp
288301771Simp#if CDCE_HAVE_NCM
289301771Simp/*------------------------------------------------------------------------*
290301771Simp *	cdce_ncm_init
291301771Simp *
292301771Simp * Return values:
293301771Simp * 0: Success
294301771Simp * Else: Failure
295301771Simp *------------------------------------------------------------------------*/
296301771Simpstatic uint8_t
297301771Simpcdce_ncm_init(struct cdce_softc *sc)
298301771Simp{
299301771Simp	struct usb_ncm_parameters temp;
300301771Simp	struct usb_device_request req;
301301771Simp	struct usb_ncm_func_descriptor *ufd;
302301771Simp	uint8_t value[8];
303301771Simp	int err;
304301771Simp
305301771Simp	ufd = usbd_find_descriptor(sc->sc_ue.ue_udev, NULL,
306301771Simp	    sc->sc_ifaces_index[1], UDESC_CS_INTERFACE, 0xFF,
307301771Simp	    UCDC_NCM_FUNC_DESC_SUBTYPE, 0xFF);
308301771Simp
309301771Simp	/* verify length of NCM functional descriptor */
310301771Simp	if (ufd != NULL) {
311301771Simp		if (ufd->bLength < sizeof(*ufd))
312301771Simp			ufd = NULL;
313301771Simp		else
314301771Simp			DPRINTFN(1, "Found NCM functional descriptor.\n");
315301771Simp	}
316301771Simp
317301771Simp	req.bmRequestType = UT_READ_CLASS_INTERFACE;
318301771Simp	req.bRequest = UCDC_NCM_GET_NTB_PARAMETERS;
319301771Simp	USETW(req.wValue, 0);
320301771Simp	req.wIndex[0] = sc->sc_ifaces_index[1];
321301771Simp	req.wIndex[1] = 0;
322301771Simp	USETW(req.wLength, sizeof(temp));
323301771Simp
324301771Simp	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
325301771Simp	    &temp, 0, NULL, 1000 /* ms */);
326301771Simp	if (err)
327301771Simp		return (1);
328301771Simp
329301771Simp	/* Read correct set of parameters according to device mode */
330301771Simp
331301771Simp	if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) {
332301771Simp		sc->sc_ncm.rx_max = UGETDW(temp.dwNtbInMaxSize);
333301771Simp		sc->sc_ncm.tx_max = UGETDW(temp.dwNtbOutMaxSize);
334301771Simp		sc->sc_ncm.tx_remainder = UGETW(temp.wNdpOutPayloadRemainder);
335301771Simp		sc->sc_ncm.tx_modulus = UGETW(temp.wNdpOutDivisor);
336301771Simp		sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpOutAlignment);
337301771Simp		sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams);
338301771Simp	} else {
339301771Simp		sc->sc_ncm.rx_max = UGETDW(temp.dwNtbOutMaxSize);
340301771Simp		sc->sc_ncm.tx_max = UGETDW(temp.dwNtbInMaxSize);
341301771Simp		sc->sc_ncm.tx_remainder = UGETW(temp.wNdpInPayloadRemainder);
342301771Simp		sc->sc_ncm.tx_modulus = UGETW(temp.wNdpInDivisor);
343301771Simp		sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpInAlignment);
344301771Simp		sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams);
345301771Simp	}
346301771Simp
347301771Simp	/* Verify maximum receive length */
348301771Simp
349301771Simp	if ((sc->sc_ncm.rx_max < 32) ||
350301771Simp	    (sc->sc_ncm.rx_max > CDCE_NCM_RX_MAXLEN)) {
351301771Simp		DPRINTFN(1, "Using default maximum receive length\n");
352301771Simp		sc->sc_ncm.rx_max = CDCE_NCM_RX_MAXLEN;
353301771Simp	}
354301771Simp
355301771Simp	/* Verify maximum transmit length */
356301771Simp
357301771Simp	if ((sc->sc_ncm.tx_max < 32) ||
358301771Simp	    (sc->sc_ncm.tx_max > CDCE_NCM_TX_MAXLEN)) {
359301771Simp		DPRINTFN(1, "Using default maximum transmit length\n");
360301771Simp		sc->sc_ncm.tx_max = CDCE_NCM_TX_MAXLEN;
361301771Simp	}
362301771Simp
363301771Simp	/*
364301771Simp	 * Verify that the structure alignment is:
365301771Simp	 * - power of two
366301771Simp	 * - not greater than the maximum transmit length
367301771Simp	 * - not less than four bytes
368301771Simp	 */
369301771Simp	if ((sc->sc_ncm.tx_struct_align < 4) ||
370301771Simp	    (sc->sc_ncm.tx_struct_align !=
371301771Simp	     ((-sc->sc_ncm.tx_struct_align) & sc->sc_ncm.tx_struct_align)) ||
372301771Simp	    (sc->sc_ncm.tx_struct_align >= sc->sc_ncm.tx_max)) {
373301771Simp		DPRINTFN(1, "Using default other alignment: 4 bytes\n");
374301771Simp		sc->sc_ncm.tx_struct_align = 4;
375301771Simp	}
376301771Simp
377301771Simp	/*
378301771Simp	 * Verify that the payload alignment is:
379301771Simp	 * - power of two
380301771Simp	 * - not greater than the maximum transmit length
381301771Simp	 * - not less than four bytes
382301771Simp	 */
383301771Simp	if ((sc->sc_ncm.tx_modulus < 4) ||
384301771Simp	    (sc->sc_ncm.tx_modulus !=
385301771Simp	     ((-sc->sc_ncm.tx_modulus) & sc->sc_ncm.tx_modulus)) ||
386301771Simp	    (sc->sc_ncm.tx_modulus >= sc->sc_ncm.tx_max)) {
387301771Simp		DPRINTFN(1, "Using default transmit modulus: 4 bytes\n");
388301771Simp		sc->sc_ncm.tx_modulus = 4;
389301771Simp	}
390301771Simp
391301771Simp	/* Verify that the payload remainder */
392301771Simp
393301771Simp	if ((sc->sc_ncm.tx_remainder >= sc->sc_ncm.tx_modulus)) {
394301771Simp		DPRINTFN(1, "Using default transmit remainder: 0 bytes\n");
395301771Simp		sc->sc_ncm.tx_remainder = 0;
396301771Simp	}
397301771Simp
398301771Simp	/*
399301771Simp	 * Offset the TX remainder so that IP packet payload starts at
400301771Simp	 * the tx_modulus. This is not too clear in the specification.
401301771Simp	 */
402301771Simp
403301771Simp	sc->sc_ncm.tx_remainder =
404301771Simp	    (sc->sc_ncm.tx_remainder - ETHER_HDR_LEN) &
405301771Simp	    (sc->sc_ncm.tx_modulus - 1);
406301771Simp
407301771Simp	/* Verify max datagrams */
408301771Simp
409301771Simp	if (sc->sc_ncm.tx_nframe == 0 ||
410301771Simp	    sc->sc_ncm.tx_nframe > (CDCE_NCM_SUBFRAMES_MAX - 1)) {
411301771Simp		DPRINTFN(1, "Using default max "
412301771Simp		    "subframes: %u units\n", CDCE_NCM_SUBFRAMES_MAX - 1);
413301771Simp		/* need to reserve one entry for zero padding */
414301771Simp		sc->sc_ncm.tx_nframe = (CDCE_NCM_SUBFRAMES_MAX - 1);
415301771Simp	}
416301771Simp
417301771Simp	/* Additional configuration, will fail in device side mode, which is OK. */
418301771Simp
419301771Simp	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
420301771Simp	req.bRequest = UCDC_NCM_SET_NTB_INPUT_SIZE;
421301771Simp	USETW(req.wValue, 0);
422301771Simp	req.wIndex[0] = sc->sc_ifaces_index[1];
423301771Simp	req.wIndex[1] = 0;
424301771Simp
425301771Simp	if (ufd != NULL &&
426301771Simp	    (ufd->bmNetworkCapabilities & UCDC_NCM_CAP_MAX_DGRAM)) {
427301771Simp		USETW(req.wLength, 8);
428301771Simp		USETDW(value, sc->sc_ncm.rx_max);
429301771Simp		USETW(value + 4, (CDCE_NCM_SUBFRAMES_MAX - 1));
430301771Simp		USETW(value + 6, 0);
431301771Simp	} else {
432301771Simp		USETW(req.wLength, 4);
433301771Simp		USETDW(value, sc->sc_ncm.rx_max);
434301771Simp 	}
435301771Simp
436301771Simp	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
437301771Simp	    &value, 0, NULL, 1000 /* ms */);
438301771Simp	if (err) {
439301771Simp		DPRINTFN(1, "Setting input size "
440301771Simp		    "to %u failed.\n", sc->sc_ncm.rx_max);
441301771Simp	}
442301771Simp
443301771Simp	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
444301771Simp	req.bRequest = UCDC_NCM_SET_CRC_MODE;
445301771Simp	USETW(req.wValue, 0);	/* no CRC */
446301771Simp	req.wIndex[0] = sc->sc_ifaces_index[1];
447301771Simp	req.wIndex[1] = 0;
448301771Simp	USETW(req.wLength, 0);
449301771Simp
450301771Simp	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
451301771Simp	    NULL, 0, NULL, 1000 /* ms */);
452301771Simp	if (err) {
453301771Simp		DPRINTFN(1, "Setting CRC mode to off failed.\n");
454301771Simp	}
455301771Simp
456301771Simp	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
457301771Simp	req.bRequest = UCDC_NCM_SET_NTB_FORMAT;
458301771Simp	USETW(req.wValue, 0);	/* NTB-16 */
459301771Simp	req.wIndex[0] = sc->sc_ifaces_index[1];
460301771Simp	req.wIndex[1] = 0;
461301771Simp	USETW(req.wLength, 0);
462301771Simp
463301771Simp	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
464301771Simp	    NULL, 0, NULL, 1000 /* ms */);
465301771Simp	if (err) {
466301771Simp		DPRINTFN(1, "Setting NTB format to 16-bit failed.\n");
467301771Simp	}
468301771Simp
469301771Simp	return (0);		/* success */
470301771Simp}
471301771Simp#endif
472301771Simp
473301771Simpstatic int
474301771Simpcdce_probe(device_t dev)
475301771Simp{
476301771Simp	struct usb_attach_arg *uaa = device_get_ivars(dev);
477301771Simp	int error;
478301771Simp
479301771Simp	error = usbd_lookup_id_by_uaa(cdce_host_devs, sizeof(cdce_host_devs), uaa);
480301771Simp	if (error)
481301771Simp		error = usbd_lookup_id_by_uaa(cdce_dual_devs, sizeof(cdce_dual_devs), uaa);
482301771Simp	return (error);
483301771Simp}
484301771Simp
485301771Simpstatic void
486301771Simpcdce_attach_post(struct usb_ether *ue)
487301771Simp{
488301771Simp	/* no-op */
489301771Simp	return;
490301771Simp}
491301771Simp
492301771Simpstatic int
493301771Simpcdce_attach(device_t dev)
494301771Simp{
495301771Simp	struct cdce_softc *sc = device_get_softc(dev);
496301771Simp	struct usb_ether *ue = &sc->sc_ue;
497301771Simp	struct usb_attach_arg *uaa = device_get_ivars(dev);
498301771Simp	struct usb_interface *iface;
499301771Simp	const struct usb_cdc_union_descriptor *ud;
500301771Simp	const struct usb_interface_descriptor *id;
501301771Simp	const struct usb_cdc_ethernet_descriptor *ued;
502301771Simp	const struct usb_config *pcfg;
503301771Simp	uint32_t seed;
504301771Simp	int error;
505301771Simp	uint8_t i;
506301771Simp	uint8_t data_iface_no;
507301771Simp	char eaddr_str[5 * ETHER_ADDR_LEN];	/* approx */
508301771Simp
509301771Simp	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
510301771Simp	sc->sc_ue.ue_udev = uaa->device;
511301771Simp
512301771Simp	device_set_usb_desc(dev);
513301771Simp
514301771Simp	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
515301771Simp
516301771Simp	ud = usbd_find_descriptor
517301771Simp	    (uaa->device, NULL, uaa->info.bIfaceIndex,
518301771Simp	    UDESC_CS_INTERFACE, 0xFF, UDESCSUB_CDC_UNION, 0xFF);
519301771Simp
520301771Simp	if ((ud == NULL) || (ud->bLength < sizeof(*ud)) ||
521301771Simp	    (sc->sc_flags & CDCE_FLAG_NO_UNION)) {
522301771Simp		DPRINTFN(1, "No union descriptor!\n");
523301771Simp		sc->sc_ifaces_index[0] = uaa->info.bIfaceIndex;
524301771Simp		sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex;
525301771Simp		goto alloc_transfers;
526301771Simp	}
527301771Simp	data_iface_no = ud->bSlaveInterface[0];
528301771Simp
529301771Simp	for (i = 0;; i++) {
530301771Simp
531301771Simp		iface = usbd_get_iface(uaa->device, i);
532301771Simp
533301771Simp		if (iface) {
534301771Simp
535301771Simp			id = usbd_get_interface_descriptor(iface);
536301771Simp
537301771Simp			if (id && (id->bInterfaceNumber == data_iface_no)) {
538301771Simp				sc->sc_ifaces_index[0] = i;
539301771Simp				sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex;
540301771Simp				usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
541301771Simp				break;
542301771Simp			}
543301771Simp		} else {
544301771Simp			device_printf(dev, "no data interface found\n");
545301771Simp			goto detach;
546301771Simp		}
547301771Simp	}
548301771Simp
549301771Simp	/*
550301771Simp	 * <quote>
551301771Simp	 *
552301771Simp	 *  The Data Class interface of a networking device shall have
553301771Simp	 *  a minimum of two interface settings. The first setting
554301771Simp	 *  (the default interface setting) includes no endpoints and
555301771Simp	 *  therefore no networking traffic is exchanged whenever the
556301771Simp	 *  default interface setting is selected. One or more
557301771Simp	 *  additional interface settings are used for normal
558301771Simp	 *  operation, and therefore each includes a pair of endpoints
559301771Simp	 *  (one IN, and one OUT) to exchange network traffic. Select
560301771Simp	 *  an alternate interface setting to initialize the network
561301771Simp	 *  aspects of the device and to enable the exchange of
562301771Simp	 *  network traffic.
563301771Simp	 *
564301771Simp	 * </quote>
565301771Simp	 *
566301771Simp	 * Some devices, most notably cable modems, include interface
567301771Simp	 * settings that have no IN or OUT endpoint, therefore loop
568301771Simp	 * through the list of all available interface settings
569301771Simp	 * looking for one with both IN and OUT endpoints.
570301771Simp	 */
571301771Simp
572301771Simpalloc_transfers:
573301771Simp
574301771Simp	pcfg = cdce_config;	/* Default Configuration */
575301771Simp
576301771Simp	for (i = 0; i != 32; i++) {
577301771Simp
578301771Simp		error = usbd_set_alt_interface_index(uaa->device,
579301771Simp		    sc->sc_ifaces_index[0], i);
580301771Simp		if (error)
581301771Simp			break;
582301771Simp#if CDCE_HAVE_NCM
583301771Simp		if ((i == 0) && (cdce_ncm_init(sc) == 0))
584301771Simp			pcfg = cdce_ncm_config;
585301771Simp#endif
586301771Simp		error = usbd_transfer_setup(uaa->device,
587301771Simp		    sc->sc_ifaces_index, sc->sc_xfer,
588301771Simp		    pcfg, CDCE_N_TRANSFER, sc, &sc->sc_mtx);
589301771Simp
590301771Simp		if (error == 0)
591301771Simp			break;
592301771Simp	}
593301771Simp
594301771Simp	if (error || (i == 32)) {
595301771Simp		device_printf(dev, "No valid alternate "
596301771Simp		    "setting found\n");
597301771Simp		goto detach;
598301771Simp	}
599301771Simp
600301771Simp	ued = usbd_find_descriptor
601301771Simp	    (uaa->device, NULL, uaa->info.bIfaceIndex,
602301771Simp	    UDESC_CS_INTERFACE, 0xFF, UDESCSUB_CDC_ENF, 0xFF);
603301771Simp
604301771Simp	if ((ued == NULL) || (ued->bLength < sizeof(*ued))) {
605301771Simp		error = USB_ERR_INVAL;
606301771Simp	} else {
607301771Simp		error = usbd_req_get_string_any(uaa->device, NULL,
608301771Simp		    eaddr_str, sizeof(eaddr_str), ued->iMacAddress);
609301771Simp	}
610301771Simp
611301771Simp	if (error) {
612301771Simp
613301771Simp		/* fake MAC address */
614301771Simp
615301771Simp		device_printf(dev, "faking MAC address\n");
616301771Simp		seed = ticks;
617301771Simp		sc->sc_ue.ue_eaddr[0] = 0x2a;
618301771Simp		memcpy(&sc->sc_ue.ue_eaddr[1], &seed, sizeof(uint32_t));
619301771Simp		sc->sc_ue.ue_eaddr[5] = device_get_unit(dev);
620301771Simp
621301771Simp	} else {
622301771Simp
623301771Simp		memset(sc->sc_ue.ue_eaddr, 0, sizeof(sc->sc_ue.ue_eaddr));
624301771Simp
625301771Simp		for (i = 0; i != (ETHER_ADDR_LEN * 2); i++) {
626301771Simp
627301771Simp			char c = eaddr_str[i];
628301771Simp
629301771Simp			if ('0' <= c && c <= '9')
630301771Simp				c -= '0';
631301771Simp			else if (c != 0)
632301771Simp				c -= 'A' - 10;
633301771Simp			else
634301771Simp				break;
635301771Simp
636301771Simp			c &= 0xf;
637301771Simp
638301771Simp			if ((i & 1) == 0)
639301771Simp				c <<= 4;
640301771Simp			sc->sc_ue.ue_eaddr[i / 2] |= c;
641301771Simp		}
642301771Simp
643301771Simp		if (uaa->usb_mode == USB_MODE_DEVICE) {
644301771Simp			/*
645301771Simp			 * Do not use the same MAC address like the peer !
646301771Simp			 */
647301771Simp			sc->sc_ue.ue_eaddr[5] ^= 0xFF;
648301771Simp		}
649301771Simp	}
650301771Simp
651301771Simp	ue->ue_sc = sc;
652301771Simp	ue->ue_dev = dev;
653301771Simp	ue->ue_udev = uaa->device;
654301771Simp	ue->ue_mtx = &sc->sc_mtx;
655301771Simp	ue->ue_methods = &cdce_ue_methods;
656301771Simp
657301771Simp	error = uether_ifattach(ue);
658301771Simp	if (error) {
659301771Simp		device_printf(dev, "could not attach interface\n");
660301771Simp		goto detach;
661301771Simp	}
662301771Simp	return (0);			/* success */
663301771Simp
664301771Simpdetach:
665301771Simp	cdce_detach(dev);
666301771Simp	return (ENXIO);			/* failure */
667301771Simp}
668301771Simp
669301771Simpstatic int
670301771Simpcdce_detach(device_t dev)
671301771Simp{
672301771Simp	struct cdce_softc *sc = device_get_softc(dev);
673301771Simp	struct usb_ether *ue = &sc->sc_ue;
674301771Simp
675301771Simp	/* stop all USB transfers first */
676301771Simp	usbd_transfer_unsetup(sc->sc_xfer, CDCE_N_TRANSFER);
677301771Simp	uether_ifdetach(ue);
678301771Simp	mtx_destroy(&sc->sc_mtx);
679301771Simp
680301771Simp	return (0);
681301771Simp}
682301771Simp
683301771Simpstatic void
684301771Simpcdce_start(struct usb_ether *ue)
685301771Simp{
686301771Simp	struct cdce_softc *sc = uether_getsc(ue);
687301771Simp
688301771Simp	/*
689301771Simp	 * Start the USB transfers, if not already started:
690301771Simp	 */
691301771Simp	usbd_transfer_start(sc->sc_xfer[CDCE_BULK_TX]);
692301771Simp	usbd_transfer_start(sc->sc_xfer[CDCE_BULK_RX]);
693301771Simp}
694301771Simp
695301771Simpstatic void
696301771Simpcdce_free_queue(struct mbuf **ppm, uint8_t n)
697301771Simp{
698301771Simp	uint8_t x;
699301771Simp	for (x = 0; x != n; x++) {
700301771Simp		if (ppm[x] != NULL) {
701301771Simp			m_freem(ppm[x]);
702301771Simp			ppm[x] = NULL;
703301771Simp		}
704301771Simp	}
705301771Simp}
706301771Simp
707301771Simpstatic void
708301771Simpcdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
709301771Simp{
710301771Simp	struct cdce_softc *sc = usbd_xfer_softc(xfer);
711301771Simp	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
712301771Simp	struct mbuf *m;
713301771Simp	struct mbuf *mt;
714301771Simp	uint32_t crc;
715301771Simp	uint8_t x;
716301771Simp	int actlen, aframes;
717301771Simp
718301771Simp	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
719301771Simp
720301771Simp	DPRINTFN(1, "\n");
721301771Simp
722301771Simp	switch (USB_GET_STATE(xfer)) {
723301771Simp	case USB_ST_TRANSFERRED:
724301771Simp		DPRINTFN(11, "transfer complete: %u bytes in %u frames\n",
725301771Simp		    actlen, aframes);
726301771Simp
727301771Simp		ifp->if_opackets++;
728301771Simp
729301771Simp		/* free all previous TX buffers */
730301771Simp		cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX);
731301771Simp
732301771Simp		/* FALLTHROUGH */
733301771Simp	case USB_ST_SETUP:
734301771Simptr_setup:
735301771Simp		for (x = 0; x != CDCE_FRAMES_MAX; x++) {
736301771Simp
737301771Simp			IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
738301771Simp
739301771Simp			if (m == NULL)
740301771Simp				break;
741301771Simp
742301771Simp			if (sc->sc_flags & CDCE_FLAG_ZAURUS) {
743301771Simp				/*
744301771Simp				 * Zaurus wants a 32-bit CRC appended
745301771Simp				 * to every frame
746301771Simp				 */
747301771Simp
748301771Simp				crc = cdce_m_crc32(m, 0, m->m_pkthdr.len);
749301771Simp				crc = htole32(crc);
750301771Simp
751301771Simp				if (!m_append(m, 4, (void *)&crc)) {
752301771Simp					m_freem(m);
753301771Simp					ifp->if_oerrors++;
754301771Simp					continue;
755301771Simp				}
756301771Simp			}
757301771Simp			if (m->m_len != m->m_pkthdr.len) {
758301771Simp				mt = m_defrag(m, M_NOWAIT);
759301771Simp				if (mt == NULL) {
760301771Simp					m_freem(m);
761301771Simp					ifp->if_oerrors++;
762301771Simp					continue;
763301771Simp				}
764301771Simp				m = mt;
765301771Simp			}
766301771Simp			if (m->m_pkthdr.len > MCLBYTES) {
767301771Simp				m->m_pkthdr.len = MCLBYTES;
768301771Simp			}
769301771Simp			sc->sc_tx_buf[x] = m;
770301771Simp			usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len);
771301771Simp
772301771Simp			/*
773301771Simp			 * If there's a BPF listener, bounce a copy of
774301771Simp			 * this frame to him:
775301771Simp			 */
776301771Simp			BPF_MTAP(ifp, m);
777301771Simp		}
778301771Simp		if (x != 0) {
779301771Simp			usbd_xfer_set_frames(xfer, x);
780301771Simp
781301771Simp			usbd_transfer_submit(xfer);
782301771Simp		}
783301771Simp		break;
784301771Simp
785301771Simp	default:			/* Error */
786301771Simp		DPRINTFN(11, "transfer error, %s\n",
787301771Simp		    usbd_errstr(error));
788301771Simp
789301771Simp		/* free all previous TX buffers */
790301771Simp		cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX);
791301771Simp
792301771Simp		/* count output errors */
793301771Simp		ifp->if_oerrors++;
794301771Simp
795301771Simp		if (error != USB_ERR_CANCELLED) {
796301771Simp			/* try to clear stall first */
797301771Simp			usbd_xfer_set_stall(xfer);
798301771Simp			goto tr_setup;
799301771Simp		}
800301771Simp		break;
801301771Simp	}
802301771Simp}
803301771Simp
804301771Simpstatic int32_t
805301771Simpcdce_m_crc32_cb(void *arg, void *src, uint32_t count)
806301771Simp{
807301771Simp	uint32_t *p_crc = arg;
808301771Simp
809301771Simp	*p_crc = crc32_raw(src, count, *p_crc);
810301771Simp	return (0);
811301771Simp}
812301771Simp
813301771Simpstatic uint32_t
814301771Simpcdce_m_crc32(struct mbuf *m, uint32_t src_offset, uint32_t src_len)
815301771Simp{
816301771Simp	uint32_t crc = 0xFFFFFFFF;
817301771Simp	int error;
818301771Simp
819301771Simp	error = m_apply(m, src_offset, src_len, cdce_m_crc32_cb, &crc);
820301771Simp	return (crc ^ 0xFFFFFFFF);
821301771Simp}
822301771Simp
823301771Simpstatic void
824301771Simpcdce_init(struct usb_ether *ue)
825301771Simp{
826301771Simp	struct cdce_softc *sc = uether_getsc(ue);
827301771Simp	struct ifnet *ifp = uether_getifp(ue);
828301771Simp
829301771Simp	CDCE_LOCK_ASSERT(sc, MA_OWNED);
830301771Simp
831301771Simp	ifp->if_drv_flags |= IFF_DRV_RUNNING;
832301771Simp
833301771Simp	/* start interrupt transfer */
834301771Simp	usbd_transfer_start(sc->sc_xfer[CDCE_INTR_RX]);
835301771Simp	usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]);
836301771Simp
837301771Simp	/* stall data write direction, which depends on USB mode */
838301771Simp	usbd_xfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]);
839301771Simp
840301771Simp	/* start data transfers */
841301771Simp	cdce_start(ue);
842301771Simp}
843301771Simp
844301771Simpstatic void
845301771Simpcdce_stop(struct usb_ether *ue)
846301771Simp{
847301771Simp	struct cdce_softc *sc = uether_getsc(ue);
848301771Simp	struct ifnet *ifp = uether_getifp(ue);
849301771Simp
850301771Simp	CDCE_LOCK_ASSERT(sc, MA_OWNED);
851301771Simp
852301771Simp	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
853301771Simp
854301771Simp	/*
855301771Simp	 * stop all the transfers, if not already stopped:
856301771Simp	 */
857301771Simp	usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_RX]);
858301771Simp	usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_TX]);
859301771Simp	usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_RX]);
860301771Simp	usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_TX]);
861301771Simp}
862301771Simp
863301771Simpstatic void
864301771Simpcdce_setmulti(struct usb_ether *ue)
865301771Simp{
866301771Simp	/* no-op */
867301771Simp	return;
868301771Simp}
869301771Simp
870301771Simpstatic void
871301771Simpcdce_setpromisc(struct usb_ether *ue)
872301771Simp{
873301771Simp	/* no-op */
874301771Simp	return;
875301771Simp}
876301771Simp
877301771Simpstatic int
878301771Simpcdce_suspend(device_t dev)
879301771Simp{
880301771Simp	device_printf(dev, "Suspending\n");
881301771Simp	return (0);
882301771Simp}
883301771Simp
884301771Simpstatic int
885301771Simpcdce_resume(device_t dev)
886301771Simp{
887301771Simp	device_printf(dev, "Resuming\n");
888301771Simp	return (0);
889301771Simp}
890301771Simp
891301771Simpstatic void
892301771Simpcdce_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
893301771Simp{
894301771Simp	struct cdce_softc *sc = usbd_xfer_softc(xfer);
895301771Simp	struct mbuf *m;
896301771Simp	uint8_t x;
897301771Simp	int actlen;
898301771Simp	int aframes;
899301771Simp	int len;
900301771Simp
901301771Simp	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
902301771Simp
903301771Simp	switch (USB_GET_STATE(xfer)) {
904301771Simp	case USB_ST_TRANSFERRED:
905301771Simp
906301771Simp		DPRINTF("received %u bytes in %u frames\n", actlen, aframes);
907301771Simp
908301771Simp		for (x = 0; x != aframes; x++) {
909301771Simp
910301771Simp			m = sc->sc_rx_buf[x];
911301771Simp			sc->sc_rx_buf[x] = NULL;
912301771Simp			len = usbd_xfer_frame_len(xfer, x);
913301771Simp
914301771Simp			/* Strip off CRC added by Zaurus, if any */
915301771Simp			if ((sc->sc_flags & CDCE_FLAG_ZAURUS) && len >= 14)
916301771Simp				len -= 4;
917301771Simp
918301771Simp			if (len < (int)sizeof(struct ether_header)) {
919301771Simp				m_freem(m);
920301771Simp				continue;
921301771Simp			}
922301771Simp			/* queue up mbuf */
923301771Simp			uether_rxmbuf(&sc->sc_ue, m, len);
924301771Simp		}
925301771Simp
926301771Simp		/* FALLTHROUGH */
927301771Simp	case USB_ST_SETUP:
928301771Simp		/*
929301771Simp		 * TODO: Implement support for multi frame transfers,
930301771Simp		 * when the USB hardware supports it.
931301771Simp		 */
932301771Simp		for (x = 0; x != 1; x++) {
933301771Simp			if (sc->sc_rx_buf[x] == NULL) {
934301771Simp				m = uether_newbuf();
935301771Simp				if (m == NULL)
936301771Simp					goto tr_stall;
937301771Simp				sc->sc_rx_buf[x] = m;
938301771Simp			} else {
939301771Simp				m = sc->sc_rx_buf[x];
940301771Simp			}
941301771Simp
942301771Simp			usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len);
943301771Simp		}
944301771Simp		/* set number of frames and start hardware */
945301771Simp		usbd_xfer_set_frames(xfer, x);
946301771Simp		usbd_transfer_submit(xfer);
947301771Simp		/* flush any received frames */
948301771Simp		uether_rxflush(&sc->sc_ue);
949301771Simp		break;
950301771Simp
951301771Simp	default:			/* Error */
952301771Simp		DPRINTF("error = %s\n",
953301771Simp		    usbd_errstr(error));
954301771Simp
955301771Simp		if (error != USB_ERR_CANCELLED) {
956301771Simptr_stall:
957301771Simp			/* try to clear stall first */
958301771Simp			usbd_xfer_set_stall(xfer);
959301771Simp			usbd_xfer_set_frames(xfer, 0);
960301771Simp			usbd_transfer_submit(xfer);
961301771Simp			break;
962301771Simp		}
963301771Simp
964301771Simp		/* need to free the RX-mbufs when we are cancelled */
965301771Simp		cdce_free_queue(sc->sc_rx_buf, CDCE_FRAMES_MAX);
966301771Simp		break;
967301771Simp	}
968301771Simp}
969301771Simp
970301771Simpstatic void
971301771Simpcdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
972301771Simp{
973301771Simp	int actlen;
974301771Simp
975301771Simp	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
976301771Simp
977301771Simp	switch (USB_GET_STATE(xfer)) {
978301771Simp	case USB_ST_TRANSFERRED:
979301771Simp
980301771Simp		DPRINTF("Received %d bytes\n", actlen);
981301771Simp
982301771Simp		/* TODO: decode some indications */
983301771Simp
984301771Simp		/* FALLTHROUGH */
985301771Simp	case USB_ST_SETUP:
986301771Simptr_setup:
987301771Simp		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
988301771Simp		usbd_transfer_submit(xfer);
989301771Simp		break;
990301771Simp
991301771Simp	default:			/* Error */
992301771Simp		if (error != USB_ERR_CANCELLED) {
993301771Simp			/* start clear stall */
994301771Simp			usbd_xfer_set_stall(xfer);
995301771Simp			goto tr_setup;
996301771Simp		}
997301771Simp		break;
998301771Simp	}
999301771Simp}
1000301771Simp
1001301771Simpstatic void
1002301771Simpcdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error)
1003301771Simp{
1004301771Simp	int actlen;
1005301771Simp
1006301771Simp	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1007301771Simp
1008301771Simp	switch (USB_GET_STATE(xfer)) {
1009301771Simp	case USB_ST_TRANSFERRED:
1010301771Simp
1011301771Simp		DPRINTF("Transferred %d bytes\n", actlen);
1012301771Simp
1013301771Simp		/* FALLTHROUGH */
1014301771Simp	case USB_ST_SETUP:
1015301771Simptr_setup:
1016301771Simp#if 0
1017301771Simp		usbd_xfer_set_frame_len(xfer, 0, XXX);
1018301771Simp		usbd_transfer_submit(xfer);
1019301771Simp#endif
1020301771Simp		break;
1021301771Simp
1022301771Simp	default:			/* Error */
1023301771Simp		if (error != USB_ERR_CANCELLED) {
1024301771Simp			/* start clear stall */
1025301771Simp			usbd_xfer_set_stall(xfer);
1026301771Simp			goto tr_setup;
1027301771Simp		}
1028301771Simp		break;
1029301771Simp	}
1030301771Simp}
1031301771Simp
1032301771Simpstatic int
1033301771Simpcdce_handle_request(device_t dev,
1034301771Simp    const void *req, void **pptr, uint16_t *plen,
1035301771Simp    uint16_t offset, uint8_t *pstate)
1036301771Simp{
1037301771Simp	return (ENXIO);			/* use builtin handler */
1038301771Simp}
1039301771Simp
1040301771Simp#if CDCE_HAVE_NCM
1041301771Simpstatic void
1042301771Simpcdce_ncm_tx_zero(struct usb_page_cache *pc,
1043301771Simp    uint32_t start, uint32_t end)
1044301771Simp{
1045301771Simp	if (start >= CDCE_NCM_TX_MAXLEN)
1046301771Simp		return;
1047301771Simp	if (end > CDCE_NCM_TX_MAXLEN)
1048301771Simp		end = CDCE_NCM_TX_MAXLEN;
1049301771Simp
1050301771Simp	usbd_frame_zero(pc, start, end - start);
1051301771Simp}
1052301771Simp
1053301771Simpstatic uint8_t
1054301771Simpcdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index)
1055301771Simp{
1056301771Simp	struct cdce_softc *sc = usbd_xfer_softc(xfer);
1057301771Simp	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
1058301771Simp	struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, index);
1059301771Simp	struct mbuf *m;
1060301771Simp	uint32_t rem;
1061301771Simp	uint32_t offset;
1062301771Simp	uint32_t last_offset;
1063301771Simp	uint16_t n;
1064301771Simp	uint8_t retval;
1065301771Simp
1066301771Simp	usbd_xfer_set_frame_offset(xfer, index * CDCE_NCM_TX_MAXLEN, index);
1067301771Simp
1068301771Simp	offset = sizeof(sc->sc_ncm.hdr) +
1069301771Simp	    sizeof(sc->sc_ncm.dpt) + sizeof(sc->sc_ncm.dp);
1070301771Simp
1071301771Simp	/* Store last valid offset before alignment */
1072301771Simp	last_offset = offset;
1073301771Simp
1074301771Simp	/* Align offset */
1075301771Simp	offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder,
1076301771Simp	    offset, sc->sc_ncm.tx_modulus);
1077301771Simp
1078301771Simp	/* Zero pad */
1079301771Simp	cdce_ncm_tx_zero(pc, last_offset, offset);
1080301771Simp
1081301771Simp	/* buffer full */
1082301771Simp	retval = 2;
1083301771Simp
1084301771Simp	for (n = 0; n != sc->sc_ncm.tx_nframe; n++) {
1085301771Simp
1086301771Simp		/* check if end of transmit buffer is reached */
1087301771Simp
1088301771Simp		if (offset >= sc->sc_ncm.tx_max)
1089301771Simp			break;
1090301771Simp
1091301771Simp		/* compute maximum buffer size */
1092301771Simp
1093301771Simp		rem = sc->sc_ncm.tx_max - offset;
1094301771Simp
1095301771Simp		IFQ_DRV_DEQUEUE(&(ifp->if_snd), m);
1096301771Simp
1097301771Simp		if (m == NULL) {
1098301771Simp			/* buffer not full */
1099301771Simp			retval = 1;
1100301771Simp			break;
1101301771Simp		}
1102301771Simp
1103301771Simp		if (m->m_pkthdr.len > (int)rem) {
1104301771Simp			if (n == 0) {
1105301771Simp				/* The frame won't fit in our buffer */
1106301771Simp				DPRINTFN(1, "Frame too big to be transmitted!\n");
1107301771Simp				m_freem(m);
1108301771Simp				ifp->if_oerrors++;
1109301771Simp				n--;
1110301771Simp				continue;
1111301771Simp			}
1112301771Simp			/* Wait till next buffer becomes ready */
1113301771Simp			IFQ_DRV_PREPEND(&(ifp->if_snd), m);
1114301771Simp			break;
1115301771Simp		}
1116301771Simp		usbd_m_copy_in(pc, offset, m, 0, m->m_pkthdr.len);
1117301771Simp
1118301771Simp		USETW(sc->sc_ncm.dp[n].wFrameLength, m->m_pkthdr.len);
1119301771Simp		USETW(sc->sc_ncm.dp[n].wFrameIndex, offset);
1120301771Simp
1121301771Simp		/* Update offset */
1122301771Simp		offset += m->m_pkthdr.len;
1123301771Simp
1124301771Simp		/* Store last valid offset before alignment */
1125301771Simp		last_offset = offset;
1126301771Simp
1127301771Simp		/* Align offset */
1128301771Simp		offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder,
1129301771Simp		    offset, sc->sc_ncm.tx_modulus);
1130301771Simp
1131301771Simp		/* Zero pad */
1132301771Simp		cdce_ncm_tx_zero(pc, last_offset, offset);
1133301771Simp
1134301771Simp		/*
1135301771Simp		 * If there's a BPF listener, bounce a copy
1136301771Simp		 * of this frame to him:
1137301771Simp		 */
1138301771Simp		BPF_MTAP(ifp, m);
1139301771Simp
1140301771Simp		/* Free mbuf */
1141301771Simp
1142301771Simp		m_freem(m);
1143301771Simp
1144301771Simp		/* Pre-increment interface counter */
1145301771Simp
1146301771Simp		ifp->if_opackets++;
1147301771Simp	}
1148301771Simp
1149301771Simp	if (n == 0)
1150301771Simp		return (0);
1151301771Simp
1152301771Simp	rem = (sizeof(sc->sc_ncm.dpt) + (4 * n) + 4);
1153
1154	USETW(sc->sc_ncm.dpt.wLength, rem);
1155
1156	/* zero the rest of the data pointer entries */
1157	for (; n != CDCE_NCM_SUBFRAMES_MAX; n++) {
1158		USETW(sc->sc_ncm.dp[n].wFrameLength, 0);
1159		USETW(sc->sc_ncm.dp[n].wFrameIndex, 0);
1160	}
1161
1162	offset = last_offset;
1163
1164	/* Align offset */
1165	offset = CDCE_NCM_ALIGN(0, offset, CDCE_NCM_TX_MINLEN);
1166
1167	/* Optimise, save bandwidth and force short termination */
1168	if (offset >= sc->sc_ncm.tx_max)
1169		offset = sc->sc_ncm.tx_max;
1170	else
1171		offset ++;
1172
1173	/* Zero pad */
1174	cdce_ncm_tx_zero(pc, last_offset, offset);
1175
1176	/* set frame length */
1177	usbd_xfer_set_frame_len(xfer, index, offset);
1178
1179	/* Fill out 16-bit header */
1180	sc->sc_ncm.hdr.dwSignature[0] = 'N';
1181	sc->sc_ncm.hdr.dwSignature[1] = 'C';
1182	sc->sc_ncm.hdr.dwSignature[2] = 'M';
1183	sc->sc_ncm.hdr.dwSignature[3] = 'H';
1184	USETW(sc->sc_ncm.hdr.wHeaderLength, sizeof(sc->sc_ncm.hdr));
1185	USETW(sc->sc_ncm.hdr.wBlockLength, offset);
1186	USETW(sc->sc_ncm.hdr.wSequence, sc->sc_ncm.tx_seq);
1187	USETW(sc->sc_ncm.hdr.wDptIndex, sizeof(sc->sc_ncm.hdr));
1188
1189	sc->sc_ncm.tx_seq++;
1190
1191	/* Fill out 16-bit frame table header */
1192	sc->sc_ncm.dpt.dwSignature[0] = 'N';
1193	sc->sc_ncm.dpt.dwSignature[1] = 'C';
1194	sc->sc_ncm.dpt.dwSignature[2] = 'M';
1195	sc->sc_ncm.dpt.dwSignature[3] = '0';
1196	USETW(sc->sc_ncm.dpt.wNextNdpIndex, 0);		/* reserved */
1197
1198	usbd_copy_in(pc, 0, &(sc->sc_ncm.hdr), sizeof(sc->sc_ncm.hdr));
1199	usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr), &(sc->sc_ncm.dpt),
1200	    sizeof(sc->sc_ncm.dpt));
1201	usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt),
1202	    &(sc->sc_ncm.dp), sizeof(sc->sc_ncm.dp));
1203	return (retval);
1204}
1205
1206static void
1207cdce_ncm_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
1208{
1209	struct cdce_softc *sc = usbd_xfer_softc(xfer);
1210	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
1211	uint16_t x;
1212	uint8_t temp;
1213	int actlen;
1214	int aframes;
1215
1216	switch (USB_GET_STATE(xfer)) {
1217	case USB_ST_TRANSFERRED:
1218
1219		usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
1220
1221		DPRINTFN(10, "transfer complete: "
1222		    "%u bytes in %u frames\n", actlen, aframes);
1223
1224	case USB_ST_SETUP:
1225		for (x = 0; x != CDCE_NCM_TX_FRAMES_MAX; x++) {
1226			temp = cdce_ncm_fill_tx_frames(xfer, x);
1227			if (temp == 0)
1228				break;
1229			if (temp == 1) {
1230				x++;
1231				break;
1232			}
1233		}
1234
1235		if (x != 0) {
1236#ifdef USB_DEBUG
1237			usbd_xfer_set_interval(xfer, cdce_tx_interval);
1238#endif
1239			usbd_xfer_set_frames(xfer, x);
1240			usbd_transfer_submit(xfer);
1241		}
1242		break;
1243
1244	default:			/* Error */
1245		DPRINTFN(10, "Transfer error: %s\n",
1246		    usbd_errstr(error));
1247
1248		/* update error counter */
1249		ifp->if_oerrors += 1;
1250
1251		if (error != USB_ERR_CANCELLED) {
1252			/* try to clear stall first */
1253			usbd_xfer_set_stall(xfer);
1254			usbd_xfer_set_frames(xfer, 0);
1255			usbd_transfer_submit(xfer);
1256		}
1257		break;
1258	}
1259}
1260
1261static void
1262cdce_ncm_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
1263{
1264	struct cdce_softc *sc = usbd_xfer_softc(xfer);
1265	struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0);
1266	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
1267	struct mbuf *m;
1268	int sumdata;
1269	int sumlen;
1270	int actlen;
1271	int aframes;
1272	int temp;
1273	int nframes;
1274	int x;
1275	int offset;
1276
1277	switch (USB_GET_STATE(xfer)) {
1278	case USB_ST_TRANSFERRED:
1279
1280		usbd_xfer_status(xfer, &actlen, &sumlen, &aframes, NULL);
1281
1282		DPRINTFN(1, "received %u bytes in %u frames\n",
1283		    actlen, aframes);
1284
1285		if (actlen < (int)(sizeof(sc->sc_ncm.hdr) +
1286		    sizeof(sc->sc_ncm.dpt))) {
1287			DPRINTFN(1, "frame too short\n");
1288			goto tr_setup;
1289		}
1290		usbd_copy_out(pc, 0, &(sc->sc_ncm.hdr),
1291		    sizeof(sc->sc_ncm.hdr));
1292
1293		if ((sc->sc_ncm.hdr.dwSignature[0] != 'N') ||
1294		    (sc->sc_ncm.hdr.dwSignature[1] != 'C') ||
1295		    (sc->sc_ncm.hdr.dwSignature[2] != 'M') ||
1296		    (sc->sc_ncm.hdr.dwSignature[3] != 'H')) {
1297			DPRINTFN(1, "invalid HDR signature: "
1298			    "0x%02x:0x%02x:0x%02x:0x%02x\n",
1299			    sc->sc_ncm.hdr.dwSignature[0],
1300			    sc->sc_ncm.hdr.dwSignature[1],
1301			    sc->sc_ncm.hdr.dwSignature[2],
1302			    sc->sc_ncm.hdr.dwSignature[3]);
1303			goto tr_stall;
1304		}
1305		temp = UGETW(sc->sc_ncm.hdr.wBlockLength);
1306		if (temp > sumlen) {
1307			DPRINTFN(1, "unsupported block length %u/%u\n",
1308			    temp, sumlen);
1309			goto tr_stall;
1310		}
1311		temp = UGETW(sc->sc_ncm.hdr.wDptIndex);
1312		if ((int)(temp + sizeof(sc->sc_ncm.dpt)) > actlen) {
1313			DPRINTFN(1, "invalid DPT index: 0x%04x\n", temp);
1314			goto tr_stall;
1315		}
1316		usbd_copy_out(pc, temp, &(sc->sc_ncm.dpt),
1317		    sizeof(sc->sc_ncm.dpt));
1318
1319		if ((sc->sc_ncm.dpt.dwSignature[0] != 'N') ||
1320		    (sc->sc_ncm.dpt.dwSignature[1] != 'C') ||
1321		    (sc->sc_ncm.dpt.dwSignature[2] != 'M') ||
1322		    (sc->sc_ncm.dpt.dwSignature[3] != '0')) {
1323			DPRINTFN(1, "invalid DPT signature"
1324			    "0x%02x:0x%02x:0x%02x:0x%02x\n",
1325			    sc->sc_ncm.dpt.dwSignature[0],
1326			    sc->sc_ncm.dpt.dwSignature[1],
1327			    sc->sc_ncm.dpt.dwSignature[2],
1328			    sc->sc_ncm.dpt.dwSignature[3]);
1329			goto tr_stall;
1330		}
1331		nframes = UGETW(sc->sc_ncm.dpt.wLength) / 4;
1332
1333		/* Subtract size of header and last zero padded entry */
1334		if (nframes >= (2 + 1))
1335			nframes -= (2 + 1);
1336		else
1337			nframes = 0;
1338
1339		DPRINTFN(1, "nframes = %u\n", nframes);
1340
1341		temp += sizeof(sc->sc_ncm.dpt);
1342
1343		if ((temp + (4 * nframes)) > actlen)
1344			goto tr_stall;
1345
1346		if (nframes > CDCE_NCM_SUBFRAMES_MAX) {
1347			DPRINTFN(1, "Truncating number of frames from %u to %u\n",
1348			    nframes, CDCE_NCM_SUBFRAMES_MAX);
1349			nframes = CDCE_NCM_SUBFRAMES_MAX;
1350		}
1351		usbd_copy_out(pc, temp, &(sc->sc_ncm.dp), (4 * nframes));
1352
1353		sumdata = 0;
1354
1355		for (x = 0; x != nframes; x++) {
1356
1357			offset = UGETW(sc->sc_ncm.dp[x].wFrameIndex);
1358			temp = UGETW(sc->sc_ncm.dp[x].wFrameLength);
1359
1360			if ((offset == 0) ||
1361			    (temp < (int)sizeof(struct ether_header)) ||
1362			    (temp > (MCLBYTES - ETHER_ALIGN))) {
1363				DPRINTFN(1, "NULL frame detected at %d\n", x);
1364				m = NULL;
1365				/* silently ignore this frame */
1366				continue;
1367			} else if ((offset + temp) > actlen) {
1368				DPRINTFN(1, "invalid frame "
1369				    "detected at %d\n", x);
1370				m = NULL;
1371				/* silently ignore this frame */
1372				continue;
1373			} else if (temp > (int)(MHLEN - ETHER_ALIGN)) {
1374				m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1375			} else {
1376				m = m_gethdr(M_NOWAIT, MT_DATA);
1377			}
1378
1379			DPRINTFN(16, "frame %u, offset = %u, length = %u \n",
1380			    x, offset, temp);
1381
1382			/* check if we have a buffer */
1383			if (m) {
1384				m_adj(m, ETHER_ALIGN);
1385
1386				usbd_copy_out(pc, offset, m->m_data, temp);
1387
1388				/* enqueue */
1389				uether_rxmbuf(&sc->sc_ue, m, temp);
1390
1391				sumdata += temp;
1392			} else {
1393				ifp->if_ierrors++;
1394			}
1395		}
1396
1397		DPRINTFN(1, "Efficiency: %u/%u bytes\n", sumdata, actlen);
1398
1399	case USB_ST_SETUP:
1400tr_setup:
1401		usbd_xfer_set_frame_len(xfer, 0, sc->sc_ncm.rx_max);
1402		usbd_xfer_set_frames(xfer, 1);
1403		usbd_transfer_submit(xfer);
1404		uether_rxflush(&sc->sc_ue);	/* must be last */
1405		break;
1406
1407	default:			/* Error */
1408		DPRINTFN(1, "error = %s\n",
1409		    usbd_errstr(error));
1410
1411		if (error != USB_ERR_CANCELLED) {
1412tr_stall:
1413			/* try to clear stall first */
1414			usbd_xfer_set_stall(xfer);
1415			usbd_xfer_set_frames(xfer, 0);
1416			usbd_transfer_submit(xfer);
1417		}
1418		break;
1419	}
1420}
1421#endif
1422