udbp.c revision 185950
1/*-
2 * Copyright (c) 1996-2000 Whistle Communications, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of author nor the names of its
14 *    contributors may be used to endorse or promote products derived
15 *    from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY NICK HIBMA AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/usb2/misc/udbp2.c 185950 2008-12-11 23:17:48Z thompsa $");
33
34/* Driver for arbitrary double bulk pipe devices.
35 * The driver assumes that there will be the same driver on the other side.
36 *
37 * XXX Some more information on what the framing of the IP packets looks like.
38 *
39 * To take full advantage of bulk transmission, packets should be chosen
40 * between 1k and 5k in size (1k to make sure the sending side starts
41 * streaming, and <5k to avoid overflowing the system with small TDs).
42 */
43
44
45/* probe/attach/detach:
46 *  Connect the driver to the hardware and netgraph
47 *
48 *  The reason we submit a bulk in transfer is that USB does not know about
49 *  interrupts. The bulk transfer continuously polls the device for data.
50 *  While the device has no data available, the device NAKs the TDs. As soon
51 *  as there is data, the transfer happens and the data comes flowing in.
52 *
53 *  In case you were wondering, interrupt transfers happen exactly that way.
54 *  It therefore doesn't make sense to use the interrupt pipe to signal
55 *  'data ready' and then schedule a bulk transfer to fetch it. That would
56 *  incur a 2ms delay at least, without reducing bandwidth requirements.
57 *
58 */
59
60#include <dev/usb2/include/usb2_devid.h>
61#include <dev/usb2/include/usb2_standard.h>
62#include <dev/usb2/include/usb2_mfunc.h>
63#include <dev/usb2/include/usb2_error.h>
64
65#define	USB_DEBUG_VAR udbp_debug
66
67#include <dev/usb2/core/usb2_core.h>
68#include <dev/usb2/core/usb2_debug.h>
69#include <dev/usb2/core/usb2_parse.h>
70#include <dev/usb2/core/usb2_lookup.h>
71#include <dev/usb2/core/usb2_util.h>
72#include <dev/usb2/core/usb2_busdma.h>
73
74#include <sys/mbuf.h>
75
76#include <netgraph/ng_message.h>
77#include <netgraph/netgraph.h>
78#include <netgraph/ng_parse.h>
79#include <netgraph/bluetooth/include/ng_bluetooth.h>
80
81#include <dev/usb2/misc/udbp2.h>
82
83#if USB_DEBUG
84static int udbp_debug = 0;
85
86SYSCTL_NODE(_hw_usb2, OID_AUTO, udbp, CTLFLAG_RW, 0, "USB udbp");
87SYSCTL_INT(_hw_usb2_udbp, OID_AUTO, debug, CTLFLAG_RW,
88    &udbp_debug, 0, "udbp debug level");
89#endif
90
91#define	UDBP_TIMEOUT	2000		/* timeout on outbound transfers, in
92					 * msecs */
93#define	UDBP_BUFFERSIZE	MCLBYTES	/* maximum number of bytes in one
94					 * transfer */
95#define	UDBP_T_WR       0
96#define	UDBP_T_RD       1
97#define	UDBP_T_WR_CS    2
98#define	UDBP_T_RD_CS    3
99#define	UDBP_T_MAX      4
100#define	UDBP_Q_MAXLEN   50
101
102struct udbp_softc {
103
104	struct mtx sc_mtx;
105	struct ng_bt_mbufq sc_xmitq_hipri;	/* hi-priority transmit queue */
106	struct ng_bt_mbufq sc_xmitq;	/* low-priority transmit queue */
107
108	struct usb2_xfer *sc_xfer[UDBP_T_MAX];
109	node_p	sc_node;		/* back pointer to node */
110	hook_p	sc_hook;		/* pointer to the hook */
111	struct mbuf *sc_bulk_in_buffer;
112
113	uint32_t sc_packets_in;		/* packets in from downstream */
114	uint32_t sc_packets_out;	/* packets out towards downstream */
115
116	uint8_t	sc_flags;
117#define	UDBP_FLAG_READ_STALL    0x01	/* read transfer stalled */
118#define	UDBP_FLAG_WRITE_STALL   0x02	/* write transfer stalled */
119
120	uint8_t	sc_name[16];
121};
122
123/* prototypes */
124
125static int udbp_modload(module_t mod, int event, void *data);
126
127static device_probe_t udbp_probe;
128static device_attach_t udbp_attach;
129static device_detach_t udbp_detach;
130
131static usb2_callback_t udbp_bulk_read_callback;
132static usb2_callback_t udbp_bulk_read_clear_stall_callback;
133static usb2_callback_t udbp_bulk_write_callback;
134static usb2_callback_t udbp_bulk_write_clear_stall_callback;
135
136static void	udbp_bulk_read_complete(node_p, hook_p, void *, int);
137
138static ng_constructor_t	ng_udbp_constructor;
139static ng_rcvmsg_t	ng_udbp_rcvmsg;
140static ng_shutdown_t	ng_udbp_rmnode;
141static ng_newhook_t	ng_udbp_newhook;
142static ng_connect_t	ng_udbp_connect;
143static ng_rcvdata_t	ng_udbp_rcvdata;
144static ng_disconnect_t	ng_udbp_disconnect;
145
146/* Parse type for struct ngudbpstat */
147static const struct ng_parse_struct_field
148	ng_udbp_stat_type_fields[] = NG_UDBP_STATS_TYPE_INFO;
149
150static const struct ng_parse_type ng_udbp_stat_type = {
151	&ng_parse_struct_type,
152	&ng_udbp_stat_type_fields
153};
154
155/* List of commands and how to convert arguments to/from ASCII */
156static const struct ng_cmdlist ng_udbp_cmdlist[] = {
157	{
158		NGM_UDBP_COOKIE,
159		NGM_UDBP_GET_STATUS,
160		"getstatus",
161		NULL,
162		&ng_udbp_stat_type,
163	},
164	{
165		NGM_UDBP_COOKIE,
166		NGM_UDBP_SET_FLAG,
167		"setflag",
168		&ng_parse_int32_type,
169		NULL
170	},
171	{0}
172};
173
174/* Netgraph node type descriptor */
175static struct ng_type ng_udbp_typestruct = {
176	.version = NG_ABI_VERSION,
177	.name = NG_UDBP_NODE_TYPE,
178	.constructor = ng_udbp_constructor,
179	.rcvmsg = ng_udbp_rcvmsg,
180	.shutdown = ng_udbp_rmnode,
181	.newhook = ng_udbp_newhook,
182	.connect = ng_udbp_connect,
183	.rcvdata = ng_udbp_rcvdata,
184	.disconnect = ng_udbp_disconnect,
185	.cmdlist = ng_udbp_cmdlist,
186};
187
188/* USB config */
189static const struct usb2_config udbp_config[UDBP_T_MAX] = {
190
191	[UDBP_T_WR] = {
192		.type = UE_BULK,
193		.endpoint = UE_ADDR_ANY,
194		.direction = UE_DIR_OUT,
195		.mh.bufsize = UDBP_BUFFERSIZE,
196		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
197		.mh.callback = &udbp_bulk_write_callback,
198		.mh.timeout = UDBP_TIMEOUT,
199	},
200
201	[UDBP_T_RD] = {
202		.type = UE_BULK,
203		.endpoint = UE_ADDR_ANY,
204		.direction = UE_DIR_IN,
205		.mh.bufsize = UDBP_BUFFERSIZE,
206		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
207		.mh.callback = &udbp_bulk_read_callback,
208	},
209
210	[UDBP_T_WR_CS] = {
211		.type = UE_CONTROL,
212		.endpoint = 0x00,	/* Control pipe */
213		.direction = UE_DIR_ANY,
214		.mh.bufsize = sizeof(struct usb2_device_request),
215		.mh.flags = {},
216		.mh.callback = &udbp_bulk_write_clear_stall_callback,
217		.mh.timeout = 1000,	/* 1 second */
218		.mh.interval = 50,	/* 50ms */
219	},
220
221	[UDBP_T_RD_CS] = {
222		.type = UE_CONTROL,
223		.endpoint = 0x00,	/* Control pipe */
224		.direction = UE_DIR_ANY,
225		.mh.bufsize = sizeof(struct usb2_device_request),
226		.mh.flags = {},
227		.mh.callback = &udbp_bulk_read_clear_stall_callback,
228		.mh.timeout = 1000,	/* 1 second */
229		.mh.interval = 50,	/* 50ms */
230	},
231};
232
233static devclass_t udbp_devclass;
234
235static device_method_t udbp_methods[] = {
236	/* Device interface */
237	DEVMETHOD(device_probe, udbp_probe),
238	DEVMETHOD(device_attach, udbp_attach),
239	DEVMETHOD(device_detach, udbp_detach),
240	{0, 0}
241};
242
243static driver_t udbp_driver = {
244	.name = "udbp",
245	.methods = udbp_methods,
246	.size = sizeof(struct udbp_softc),
247};
248
249DRIVER_MODULE(udbp, ushub, udbp_driver, udbp_devclass, udbp_modload, 0);
250MODULE_DEPEND(udbp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
251MODULE_DEPEND(udbp, usb2_misc, 1, 1, 1);
252MODULE_DEPEND(udbp, usb2_core, 1, 1, 1);
253
254static int
255udbp_modload(module_t mod, int event, void *data)
256{
257	int error;
258
259	switch (event) {
260	case MOD_LOAD:
261		error = ng_newtype(&ng_udbp_typestruct);
262		if (error != 0) {
263			printf("%s: Could not register "
264			    "Netgraph node type, error=%d\n",
265			    NG_UDBP_NODE_TYPE, error);
266		}
267		break;
268
269	case MOD_UNLOAD:
270		error = ng_rmtype(&ng_udbp_typestruct);
271		break;
272
273	default:
274		error = EOPNOTSUPP;
275		break;
276	}
277	return (error);
278}
279
280static int
281udbp_probe(device_t dev)
282{
283	struct usb2_attach_arg *uaa = device_get_ivars(dev);
284
285	if (uaa->usb2_mode != USB_MODE_HOST) {
286		return (ENXIO);
287	}
288	/*
289	 * XXX Julian, add the id of the device if you have one to test
290	 * things with. run 'usbdevs -v' and note the 3 ID's that appear.
291	 * The Vendor Id and Product Id are in hex and the Revision Id is in
292	 * bcd. But as usual if the revision is 0x101 then you should
293	 * compare the revision id in the device descriptor with 0x101 Or go
294	 * search the file usbdevs.h. Maybe the device is already in there.
295	 */
296	if (((uaa->info.idVendor == USB_VENDOR_NETCHIP) &&
297	    (uaa->info.idProduct == USB_PRODUCT_NETCHIP_TURBOCONNECT)))
298		return (0);
299
300	if (((uaa->info.idVendor == USB_VENDOR_PROLIFIC) &&
301	    ((uaa->info.idProduct == USB_PRODUCT_PROLIFIC_PL2301) ||
302	    (uaa->info.idProduct == USB_PRODUCT_PROLIFIC_PL2302))))
303		return (0);
304
305	if ((uaa->info.idVendor == USB_VENDOR_ANCHOR) &&
306	    (uaa->info.idProduct == USB_PRODUCT_ANCHOR_EZLINK))
307		return (0);
308
309	if ((uaa->info.idVendor == USB_VENDOR_GENESYS) &&
310	    (uaa->info.idProduct == USB_PRODUCT_GENESYS_GL620USB))
311		return (0);
312
313	return (ENXIO);
314}
315
316static int
317udbp_attach(device_t dev)
318{
319	struct usb2_attach_arg *uaa = device_get_ivars(dev);
320	struct udbp_softc *sc = device_get_softc(dev);
321	int error;
322
323	if (sc == NULL) {
324		return (ENOMEM);
325	}
326	device_set_usb2_desc(dev);
327
328	snprintf(sc->sc_name, sizeof(sc->sc_name),
329	    "%s", device_get_nameunit(dev));
330
331	mtx_init(&sc->sc_mtx, "udbp lock", NULL, MTX_DEF | MTX_RECURSE);
332
333	error = usb2_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
334	    sc->sc_xfer, udbp_config, UDBP_T_MAX, sc, &sc->sc_mtx);
335	if (error) {
336		DPRINTF("error=%s\n", usb2_errstr(error));
337		goto detach;
338	}
339	NG_BT_MBUFQ_INIT(&sc->sc_xmitq, UDBP_Q_MAXLEN);
340
341	NG_BT_MBUFQ_INIT(&sc->sc_xmitq_hipri, UDBP_Q_MAXLEN);
342
343	/* create Netgraph node */
344
345	if (ng_make_node_common(&ng_udbp_typestruct, &sc->sc_node) != 0) {
346		printf("%s: Could not create Netgraph node\n",
347		    sc->sc_name);
348		sc->sc_node = NULL;
349		goto detach;
350	}
351	/* name node */
352
353	if (ng_name_node(sc->sc_node, sc->sc_name) != 0) {
354		printf("%s: Could not name node\n",
355		    sc->sc_name);
356		NG_NODE_UNREF(sc->sc_node);
357		sc->sc_node = NULL;
358		goto detach;
359	}
360	NG_NODE_SET_PRIVATE(sc->sc_node, sc);
361
362	/* the device is now operational */
363
364	return (0);			/* success */
365
366detach:
367	udbp_detach(dev);
368	return (ENOMEM);		/* failure */
369}
370
371static int
372udbp_detach(device_t dev)
373{
374	struct udbp_softc *sc = device_get_softc(dev);
375
376	/* destroy Netgraph node */
377
378	if (sc->sc_node != NULL) {
379		NG_NODE_SET_PRIVATE(sc->sc_node, NULL);
380		ng_rmnode_self(sc->sc_node);
381		sc->sc_node = NULL;
382	}
383	/* free USB transfers, if any */
384
385	usb2_transfer_unsetup(sc->sc_xfer, UDBP_T_MAX);
386
387	mtx_destroy(&sc->sc_mtx);
388
389	/* destroy queues */
390
391	NG_BT_MBUFQ_DESTROY(&sc->sc_xmitq);
392	NG_BT_MBUFQ_DESTROY(&sc->sc_xmitq_hipri);
393
394	/* extra check */
395
396	if (sc->sc_bulk_in_buffer) {
397		m_freem(sc->sc_bulk_in_buffer);
398		sc->sc_bulk_in_buffer = NULL;
399	}
400	return (0);			/* success */
401}
402
403static void
404udbp_bulk_read_callback(struct usb2_xfer *xfer)
405{
406	struct udbp_softc *sc = xfer->priv_sc;
407	struct mbuf *m;
408
409	switch (USB_GET_STATE(xfer)) {
410	case USB_ST_TRANSFERRED:
411
412		/* allocate new mbuf */
413
414		MGETHDR(m, M_DONTWAIT, MT_DATA);
415
416		if (m == NULL) {
417			goto tr_setup;
418		}
419		MCLGET(m, M_DONTWAIT);
420
421		if (!(m->m_flags & M_EXT)) {
422			m_freem(m);
423			goto tr_setup;
424		}
425		m->m_pkthdr.len = m->m_len = xfer->actlen;
426
427		usb2_copy_out(xfer->frbuffers, 0, m->m_data, xfer->actlen);
428
429		sc->sc_bulk_in_buffer = m;
430
431		DPRINTF("received package %d "
432		    "bytes\n", xfer->actlen);
433
434	case USB_ST_SETUP:
435tr_setup:
436		if (sc->sc_bulk_in_buffer) {
437			ng_send_fn(sc->sc_node, NULL, &udbp_bulk_read_complete, NULL, 0);
438			return;
439		}
440		if (sc->sc_flags & UDBP_FLAG_READ_STALL) {
441			usb2_transfer_start(sc->sc_xfer[UDBP_T_RD_CS]);
442			return;
443		}
444		xfer->frlengths[0] = xfer->max_data_length;
445		usb2_start_hardware(xfer);
446		return;
447
448	default:			/* Error */
449		if (xfer->error != USB_ERR_CANCELLED) {
450			/* try to clear stall first */
451			sc->sc_flags |= UDBP_FLAG_READ_STALL;
452			usb2_transfer_start(sc->sc_xfer[UDBP_T_RD_CS]);
453		}
454		return;
455
456	}
457}
458
459static void
460udbp_bulk_read_clear_stall_callback(struct usb2_xfer *xfer)
461{
462	struct udbp_softc *sc = xfer->priv_sc;
463	struct usb2_xfer *xfer_other = sc->sc_xfer[UDBP_T_RD];
464
465	if (usb2_clear_stall_callback(xfer, xfer_other)) {
466		DPRINTF("stall cleared\n");
467		sc->sc_flags &= ~UDBP_FLAG_READ_STALL;
468		usb2_transfer_start(xfer_other);
469	}
470}
471
472static void
473udbp_bulk_read_complete(node_p node, hook_p hook, void *arg1, int arg2)
474{
475	struct udbp_softc *sc = NG_NODE_PRIVATE(node);
476	struct mbuf *m;
477	int error;
478
479	if (sc == NULL) {
480		return;
481	}
482	mtx_lock(&sc->sc_mtx);
483
484	m = sc->sc_bulk_in_buffer;
485
486	if (m) {
487
488		sc->sc_bulk_in_buffer = NULL;
489
490		if ((sc->sc_hook == NULL) ||
491		    NG_HOOK_NOT_VALID(sc->sc_hook)) {
492			DPRINTF("No upstream hook\n");
493			goto done;
494		}
495		sc->sc_packets_in++;
496
497		NG_SEND_DATA_ONLY(error, sc->sc_hook, m);
498
499		m = NULL;
500	}
501done:
502	if (m) {
503		m_freem(m);
504	}
505	/* start USB bulk-in transfer, if not already started */
506
507	usb2_transfer_start(sc->sc_xfer[UDBP_T_RD]);
508
509	mtx_unlock(&sc->sc_mtx);
510}
511
512static void
513udbp_bulk_write_callback(struct usb2_xfer *xfer)
514{
515	struct udbp_softc *sc = xfer->priv_sc;
516	struct mbuf *m;
517
518	switch (USB_GET_STATE(xfer)) {
519	case USB_ST_TRANSFERRED:
520
521		sc->sc_packets_out++;
522
523	case USB_ST_SETUP:
524		if (sc->sc_flags & UDBP_FLAG_WRITE_STALL) {
525			usb2_transfer_start(sc->sc_xfer[UDBP_T_WR_CS]);
526			return;
527		}
528		/* get next mbuf, if any */
529
530		NG_BT_MBUFQ_DEQUEUE(&sc->sc_xmitq_hipri, m);
531		if (m == NULL) {
532			NG_BT_MBUFQ_DEQUEUE(&sc->sc_xmitq, m);
533			if (m == NULL) {
534				DPRINTF("Data queue is empty\n");
535				return;
536			}
537		}
538		if (m->m_pkthdr.len > MCLBYTES) {
539			DPRINTF("truncating large packet "
540			    "from %d to %d bytes\n", m->m_pkthdr.len,
541			    MCLBYTES);
542			m->m_pkthdr.len = MCLBYTES;
543		}
544		usb2_m_copy_in(xfer->frbuffers, 0, m, 0, m->m_pkthdr.len);
545
546		xfer->frlengths[0] = m->m_pkthdr.len;
547
548		m_freem(m);
549
550		DPRINTF("packet out: %d bytes\n",
551		    xfer->frlengths[0]);
552
553		usb2_start_hardware(xfer);
554		return;
555
556	default:			/* Error */
557		if (xfer->error != USB_ERR_CANCELLED) {
558			/* try to clear stall first */
559			sc->sc_flags |= UDBP_FLAG_WRITE_STALL;
560			usb2_transfer_start(sc->sc_xfer[UDBP_T_WR_CS]);
561		}
562		return;
563
564	}
565}
566
567static void
568udbp_bulk_write_clear_stall_callback(struct usb2_xfer *xfer)
569{
570	struct udbp_softc *sc = xfer->priv_sc;
571	struct usb2_xfer *xfer_other = sc->sc_xfer[UDBP_T_WR];
572
573	if (usb2_clear_stall_callback(xfer, xfer_other)) {
574		DPRINTF("stall cleared\n");
575		sc->sc_flags &= ~UDBP_FLAG_WRITE_STALL;
576		usb2_transfer_start(xfer_other);
577	}
578}
579
580/***********************************************************************
581 * Start of Netgraph methods
582 **********************************************************************/
583
584/*
585 * If this is a device node so this work is done in the attach()
586 * routine and the constructor will return EINVAL as you should not be able
587 * to create nodes that depend on hardware (unless you can add the hardware :)
588 */
589static int
590ng_udbp_constructor(node_p node)
591{
592	return (EINVAL);
593}
594
595/*
596 * Give our ok for a hook to be added...
597 * If we are not running this might kick a device into life.
598 * Possibly decode information out of the hook name.
599 * Add the hook's private info to the hook structure.
600 * (if we had some). In this example, we assume that there is a
601 * an array of structs, called 'channel' in the private info,
602 * one for each active channel. The private
603 * pointer of each hook points to the appropriate UDBP_hookinfo struct
604 * so that the source of an input packet is easily identified.
605 */
606static int
607ng_udbp_newhook(node_p node, hook_p hook, const char *name)
608{
609	struct udbp_softc *sc = NG_NODE_PRIVATE(node);
610	int32_t error = 0;
611
612	if (strcmp(name, NG_UDBP_HOOK_NAME)) {
613		return (EINVAL);
614	}
615	mtx_lock(&sc->sc_mtx);
616
617	if (sc->sc_hook != NULL) {
618		error = EISCONN;
619	} else {
620		sc->sc_hook = hook;
621		NG_HOOK_SET_PRIVATE(hook, NULL);
622	}
623
624	mtx_unlock(&sc->sc_mtx);
625
626	return (error);
627}
628
629/*
630 * Get a netgraph control message.
631 * Check it is one we understand. If needed, send a response.
632 * We could save the address for an async action later, but don't here.
633 * Always free the message.
634 * The response should be in a malloc'd region that the caller can 'free'.
635 * A response is not required.
636 * Theoretically you could respond defferently to old message types if
637 * the cookie in the header didn't match what we consider to be current
638 * (so that old userland programs could continue to work).
639 */
640static int
641ng_udbp_rcvmsg(node_p node, item_p item, hook_p lasthook)
642{
643	struct udbp_softc *sc = NG_NODE_PRIVATE(node);
644	struct ng_mesg *resp = NULL;
645	int error = 0;
646	struct ng_mesg *msg;
647
648	NGI_GET_MSG(item, msg);
649	/* Deal with message according to cookie and command */
650	switch (msg->header.typecookie) {
651	case NGM_UDBP_COOKIE:
652		switch (msg->header.cmd) {
653		case NGM_UDBP_GET_STATUS:
654			{
655				struct ngudbpstat *stats;
656
657				NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT);
658				if (!resp) {
659					error = ENOMEM;
660					break;
661				}
662				stats = (struct ngudbpstat *)resp->data;
663				mtx_lock(&sc->sc_mtx);
664				stats->packets_in = sc->sc_packets_in;
665				stats->packets_out = sc->sc_packets_out;
666				mtx_unlock(&sc->sc_mtx);
667				break;
668			}
669		case NGM_UDBP_SET_FLAG:
670			if (msg->header.arglen != sizeof(uint32_t)) {
671				error = EINVAL;
672				break;
673			}
674			DPRINTF("flags = 0x%08x\n",
675			    *((uint32_t *)msg->data));
676			break;
677		default:
678			error = EINVAL;	/* unknown command */
679			break;
680		}
681		break;
682	default:
683		error = EINVAL;		/* unknown cookie type */
684		break;
685	}
686
687	/* Take care of synchronous response, if any */
688	NG_RESPOND_MSG(error, node, item, resp);
689	NG_FREE_MSG(msg);
690	return (error);
691}
692
693/*
694 * Accept data from the hook and queue it for output.
695 */
696static int
697ng_udbp_rcvdata(hook_p hook, item_p item)
698{
699	struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
700	struct ng_bt_mbufq *queue_ptr;
701	struct mbuf *m;
702	struct ng_tag_prio *ptag;
703	int error;
704
705	if (sc == NULL) {
706		NG_FREE_ITEM(item);
707		return (EHOSTDOWN);
708	}
709	NGI_GET_M(item, m);
710	NG_FREE_ITEM(item);
711
712	/*
713	 * Now queue the data for when it can be sent
714	 */
715	ptag = (void *)m_tag_locate(m, NGM_GENERIC_COOKIE,
716	    NG_TAG_PRIO, NULL);
717
718	if (ptag && (ptag->priority > NG_PRIO_CUTOFF))
719		queue_ptr = &sc->sc_xmitq_hipri;
720	else
721		queue_ptr = &sc->sc_xmitq;
722
723	mtx_lock(&sc->sc_mtx);
724
725	if (NG_BT_MBUFQ_FULL(queue_ptr)) {
726		NG_BT_MBUFQ_DROP(queue_ptr);
727		NG_FREE_M(m);
728		error = ENOBUFS;
729	} else {
730		NG_BT_MBUFQ_ENQUEUE(queue_ptr, m);
731		/*
732		 * start bulk-out transfer, if not already started:
733		 */
734		usb2_transfer_start(sc->sc_xfer[UDBP_T_WR]);
735		error = 0;
736	}
737
738	mtx_unlock(&sc->sc_mtx);
739
740	return (error);
741}
742
743/*
744 * Do local shutdown processing..
745 * We are a persistant device, we refuse to go away, and
746 * only remove our links and reset ourself.
747 */
748static int
749ng_udbp_rmnode(node_p node)
750{
751	struct udbp_softc *sc = NG_NODE_PRIVATE(node);
752
753	/* Let old node go */
754	NG_NODE_SET_PRIVATE(node, NULL);
755	NG_NODE_UNREF(node);		/* forget it ever existed */
756
757	if (sc == NULL) {
758		goto done;
759	}
760	/* Create Netgraph node */
761	if (ng_make_node_common(&ng_udbp_typestruct, &sc->sc_node) != 0) {
762		printf("%s: Could not create Netgraph node\n",
763		    sc->sc_name);
764		sc->sc_node = NULL;
765		goto done;
766	}
767	/* Name node */
768	if (ng_name_node(sc->sc_node, sc->sc_name) != 0) {
769		printf("%s: Could not name Netgraph node\n",
770		    sc->sc_name);
771		NG_NODE_UNREF(sc->sc_node);
772		sc->sc_node = NULL;
773		goto done;
774	}
775	NG_NODE_SET_PRIVATE(sc->sc_node, sc);
776
777done:
778	if (sc) {
779		mtx_unlock(&sc->sc_mtx);
780	}
781	return (0);
782}
783
784/*
785 * This is called once we've already connected a new hook to the other node.
786 * It gives us a chance to balk at the last minute.
787 */
788static int
789ng_udbp_connect(hook_p hook)
790{
791	struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
792
793	/* probably not at splnet, force outward queueing */
794	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
795
796	mtx_lock(&sc->sc_mtx);
797
798	sc->sc_flags |= (UDBP_FLAG_READ_STALL |
799	    UDBP_FLAG_WRITE_STALL);
800
801	/* start bulk-in transfer */
802	usb2_transfer_start(sc->sc_xfer[UDBP_T_RD]);
803
804	/* start bulk-out transfer */
805	usb2_transfer_start(sc->sc_xfer[UDBP_T_WR]);
806
807	mtx_unlock(&sc->sc_mtx);
808
809	return (0);
810}
811
812/*
813 * Dook disconnection
814 *
815 * For this type, removal of the last link destroys the node
816 */
817static int
818ng_udbp_disconnect(hook_p hook)
819{
820	struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
821	int error = 0;
822
823	if (sc != NULL) {
824
825		mtx_lock(&sc->sc_mtx);
826
827		if (hook != sc->sc_hook) {
828			error = EINVAL;
829		} else {
830
831			/* stop bulk-in transfer */
832			usb2_transfer_stop(sc->sc_xfer[UDBP_T_RD_CS]);
833			usb2_transfer_stop(sc->sc_xfer[UDBP_T_RD]);
834
835			/* stop bulk-out transfer */
836			usb2_transfer_stop(sc->sc_xfer[UDBP_T_WR_CS]);
837			usb2_transfer_stop(sc->sc_xfer[UDBP_T_WR]);
838
839			/* cleanup queues */
840			NG_BT_MBUFQ_DRAIN(&sc->sc_xmitq);
841			NG_BT_MBUFQ_DRAIN(&sc->sc_xmitq_hipri);
842
843			if (sc->sc_bulk_in_buffer) {
844				m_freem(sc->sc_bulk_in_buffer);
845				sc->sc_bulk_in_buffer = NULL;
846			}
847			sc->sc_hook = NULL;
848		}
849
850		mtx_unlock(&sc->sc_mtx);
851	}
852	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
853	    && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
854		ng_rmnode_self(NG_HOOK_NODE(hook));
855
856	return (error);
857}
858