udbp.c revision 187972
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 187972 2009-02-01 01:07:15Z 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	device_set_usb2_desc(dev);
324
325	snprintf(sc->sc_name, sizeof(sc->sc_name),
326	    "%s", device_get_nameunit(dev));
327
328	mtx_init(&sc->sc_mtx, "udbp lock", NULL, MTX_DEF | MTX_RECURSE);
329
330	error = usb2_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
331	    sc->sc_xfer, udbp_config, UDBP_T_MAX, sc, &sc->sc_mtx);
332	if (error) {
333		DPRINTF("error=%s\n", usb2_errstr(error));
334		goto detach;
335	}
336	NG_BT_MBUFQ_INIT(&sc->sc_xmitq, UDBP_Q_MAXLEN);
337
338	NG_BT_MBUFQ_INIT(&sc->sc_xmitq_hipri, UDBP_Q_MAXLEN);
339
340	/* create Netgraph node */
341
342	if (ng_make_node_common(&ng_udbp_typestruct, &sc->sc_node) != 0) {
343		printf("%s: Could not create Netgraph node\n",
344		    sc->sc_name);
345		sc->sc_node = NULL;
346		goto detach;
347	}
348	/* name node */
349
350	if (ng_name_node(sc->sc_node, sc->sc_name) != 0) {
351		printf("%s: Could not name node\n",
352		    sc->sc_name);
353		NG_NODE_UNREF(sc->sc_node);
354		sc->sc_node = NULL;
355		goto detach;
356	}
357	NG_NODE_SET_PRIVATE(sc->sc_node, sc);
358
359	/* the device is now operational */
360
361	return (0);			/* success */
362
363detach:
364	udbp_detach(dev);
365	return (ENOMEM);		/* failure */
366}
367
368static int
369udbp_detach(device_t dev)
370{
371	struct udbp_softc *sc = device_get_softc(dev);
372
373	/* destroy Netgraph node */
374
375	if (sc->sc_node != NULL) {
376		NG_NODE_SET_PRIVATE(sc->sc_node, NULL);
377		ng_rmnode_self(sc->sc_node);
378		sc->sc_node = NULL;
379	}
380	/* free USB transfers, if any */
381
382	usb2_transfer_unsetup(sc->sc_xfer, UDBP_T_MAX);
383
384	mtx_destroy(&sc->sc_mtx);
385
386	/* destroy queues */
387
388	NG_BT_MBUFQ_DESTROY(&sc->sc_xmitq);
389	NG_BT_MBUFQ_DESTROY(&sc->sc_xmitq_hipri);
390
391	/* extra check */
392
393	if (sc->sc_bulk_in_buffer) {
394		m_freem(sc->sc_bulk_in_buffer);
395		sc->sc_bulk_in_buffer = NULL;
396	}
397	return (0);			/* success */
398}
399
400static void
401udbp_bulk_read_callback(struct usb2_xfer *xfer)
402{
403	struct udbp_softc *sc = xfer->priv_sc;
404	struct mbuf *m;
405
406	switch (USB_GET_STATE(xfer)) {
407	case USB_ST_TRANSFERRED:
408
409		/* allocate new mbuf */
410
411		MGETHDR(m, M_DONTWAIT, MT_DATA);
412
413		if (m == NULL) {
414			goto tr_setup;
415		}
416		MCLGET(m, M_DONTWAIT);
417
418		if (!(m->m_flags & M_EXT)) {
419			m_freem(m);
420			goto tr_setup;
421		}
422		m->m_pkthdr.len = m->m_len = xfer->actlen;
423
424		usb2_copy_out(xfer->frbuffers, 0, m->m_data, xfer->actlen);
425
426		sc->sc_bulk_in_buffer = m;
427
428		DPRINTF("received package %d "
429		    "bytes\n", xfer->actlen);
430
431	case USB_ST_SETUP:
432tr_setup:
433		if (sc->sc_bulk_in_buffer) {
434			ng_send_fn(sc->sc_node, NULL, &udbp_bulk_read_complete, NULL, 0);
435			return;
436		}
437		if (sc->sc_flags & UDBP_FLAG_READ_STALL) {
438			usb2_transfer_start(sc->sc_xfer[UDBP_T_RD_CS]);
439			return;
440		}
441		xfer->frlengths[0] = xfer->max_data_length;
442		usb2_start_hardware(xfer);
443		return;
444
445	default:			/* Error */
446		if (xfer->error != USB_ERR_CANCELLED) {
447			/* try to clear stall first */
448			sc->sc_flags |= UDBP_FLAG_READ_STALL;
449			usb2_transfer_start(sc->sc_xfer[UDBP_T_RD_CS]);
450		}
451		return;
452
453	}
454}
455
456static void
457udbp_bulk_read_clear_stall_callback(struct usb2_xfer *xfer)
458{
459	struct udbp_softc *sc = xfer->priv_sc;
460	struct usb2_xfer *xfer_other = sc->sc_xfer[UDBP_T_RD];
461
462	if (usb2_clear_stall_callback(xfer, xfer_other)) {
463		DPRINTF("stall cleared\n");
464		sc->sc_flags &= ~UDBP_FLAG_READ_STALL;
465		usb2_transfer_start(xfer_other);
466	}
467}
468
469static void
470udbp_bulk_read_complete(node_p node, hook_p hook, void *arg1, int arg2)
471{
472	struct udbp_softc *sc = NG_NODE_PRIVATE(node);
473	struct mbuf *m;
474	int error;
475
476	if (sc == NULL) {
477		return;
478	}
479	mtx_lock(&sc->sc_mtx);
480
481	m = sc->sc_bulk_in_buffer;
482
483	if (m) {
484
485		sc->sc_bulk_in_buffer = NULL;
486
487		if ((sc->sc_hook == NULL) ||
488		    NG_HOOK_NOT_VALID(sc->sc_hook)) {
489			DPRINTF("No upstream hook\n");
490			goto done;
491		}
492		sc->sc_packets_in++;
493
494		NG_SEND_DATA_ONLY(error, sc->sc_hook, m);
495
496		m = NULL;
497	}
498done:
499	if (m) {
500		m_freem(m);
501	}
502	/* start USB bulk-in transfer, if not already started */
503
504	usb2_transfer_start(sc->sc_xfer[UDBP_T_RD]);
505
506	mtx_unlock(&sc->sc_mtx);
507}
508
509static void
510udbp_bulk_write_callback(struct usb2_xfer *xfer)
511{
512	struct udbp_softc *sc = xfer->priv_sc;
513	struct mbuf *m;
514
515	switch (USB_GET_STATE(xfer)) {
516	case USB_ST_TRANSFERRED:
517
518		sc->sc_packets_out++;
519
520	case USB_ST_SETUP:
521		if (sc->sc_flags & UDBP_FLAG_WRITE_STALL) {
522			usb2_transfer_start(sc->sc_xfer[UDBP_T_WR_CS]);
523			return;
524		}
525		/* get next mbuf, if any */
526
527		NG_BT_MBUFQ_DEQUEUE(&sc->sc_xmitq_hipri, m);
528		if (m == NULL) {
529			NG_BT_MBUFQ_DEQUEUE(&sc->sc_xmitq, m);
530			if (m == NULL) {
531				DPRINTF("Data queue is empty\n");
532				return;
533			}
534		}
535		if (m->m_pkthdr.len > MCLBYTES) {
536			DPRINTF("truncating large packet "
537			    "from %d to %d bytes\n", m->m_pkthdr.len,
538			    MCLBYTES);
539			m->m_pkthdr.len = MCLBYTES;
540		}
541		usb2_m_copy_in(xfer->frbuffers, 0, m, 0, m->m_pkthdr.len);
542
543		xfer->frlengths[0] = m->m_pkthdr.len;
544
545		m_freem(m);
546
547		DPRINTF("packet out: %d bytes\n",
548		    xfer->frlengths[0]);
549
550		usb2_start_hardware(xfer);
551		return;
552
553	default:			/* Error */
554		if (xfer->error != USB_ERR_CANCELLED) {
555			/* try to clear stall first */
556			sc->sc_flags |= UDBP_FLAG_WRITE_STALL;
557			usb2_transfer_start(sc->sc_xfer[UDBP_T_WR_CS]);
558		}
559		return;
560
561	}
562}
563
564static void
565udbp_bulk_write_clear_stall_callback(struct usb2_xfer *xfer)
566{
567	struct udbp_softc *sc = xfer->priv_sc;
568	struct usb2_xfer *xfer_other = sc->sc_xfer[UDBP_T_WR];
569
570	if (usb2_clear_stall_callback(xfer, xfer_other)) {
571		DPRINTF("stall cleared\n");
572		sc->sc_flags &= ~UDBP_FLAG_WRITE_STALL;
573		usb2_transfer_start(xfer_other);
574	}
575}
576
577/***********************************************************************
578 * Start of Netgraph methods
579 **********************************************************************/
580
581/*
582 * If this is a device node so this work is done in the attach()
583 * routine and the constructor will return EINVAL as you should not be able
584 * to create nodes that depend on hardware (unless you can add the hardware :)
585 */
586static int
587ng_udbp_constructor(node_p node)
588{
589	return (EINVAL);
590}
591
592/*
593 * Give our ok for a hook to be added...
594 * If we are not running this might kick a device into life.
595 * Possibly decode information out of the hook name.
596 * Add the hook's private info to the hook structure.
597 * (if we had some). In this example, we assume that there is a
598 * an array of structs, called 'channel' in the private info,
599 * one for each active channel. The private
600 * pointer of each hook points to the appropriate UDBP_hookinfo struct
601 * so that the source of an input packet is easily identified.
602 */
603static int
604ng_udbp_newhook(node_p node, hook_p hook, const char *name)
605{
606	struct udbp_softc *sc = NG_NODE_PRIVATE(node);
607	int32_t error = 0;
608
609	if (strcmp(name, NG_UDBP_HOOK_NAME)) {
610		return (EINVAL);
611	}
612	mtx_lock(&sc->sc_mtx);
613
614	if (sc->sc_hook != NULL) {
615		error = EISCONN;
616	} else {
617		sc->sc_hook = hook;
618		NG_HOOK_SET_PRIVATE(hook, NULL);
619	}
620
621	mtx_unlock(&sc->sc_mtx);
622
623	return (error);
624}
625
626/*
627 * Get a netgraph control message.
628 * Check it is one we understand. If needed, send a response.
629 * We could save the address for an async action later, but don't here.
630 * Always free the message.
631 * The response should be in a malloc'd region that the caller can 'free'.
632 * A response is not required.
633 * Theoretically you could respond defferently to old message types if
634 * the cookie in the header didn't match what we consider to be current
635 * (so that old userland programs could continue to work).
636 */
637static int
638ng_udbp_rcvmsg(node_p node, item_p item, hook_p lasthook)
639{
640	struct udbp_softc *sc = NG_NODE_PRIVATE(node);
641	struct ng_mesg *resp = NULL;
642	int error = 0;
643	struct ng_mesg *msg;
644
645	NGI_GET_MSG(item, msg);
646	/* Deal with message according to cookie and command */
647	switch (msg->header.typecookie) {
648	case NGM_UDBP_COOKIE:
649		switch (msg->header.cmd) {
650		case NGM_UDBP_GET_STATUS:
651			{
652				struct ngudbpstat *stats;
653
654				NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT);
655				if (!resp) {
656					error = ENOMEM;
657					break;
658				}
659				stats = (struct ngudbpstat *)resp->data;
660				mtx_lock(&sc->sc_mtx);
661				stats->packets_in = sc->sc_packets_in;
662				stats->packets_out = sc->sc_packets_out;
663				mtx_unlock(&sc->sc_mtx);
664				break;
665			}
666		case NGM_UDBP_SET_FLAG:
667			if (msg->header.arglen != sizeof(uint32_t)) {
668				error = EINVAL;
669				break;
670			}
671			DPRINTF("flags = 0x%08x\n",
672			    *((uint32_t *)msg->data));
673			break;
674		default:
675			error = EINVAL;	/* unknown command */
676			break;
677		}
678		break;
679	default:
680		error = EINVAL;		/* unknown cookie type */
681		break;
682	}
683
684	/* Take care of synchronous response, if any */
685	NG_RESPOND_MSG(error, node, item, resp);
686	NG_FREE_MSG(msg);
687	return (error);
688}
689
690/*
691 * Accept data from the hook and queue it for output.
692 */
693static int
694ng_udbp_rcvdata(hook_p hook, item_p item)
695{
696	struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
697	struct ng_bt_mbufq *queue_ptr;
698	struct mbuf *m;
699	struct ng_tag_prio *ptag;
700	int error;
701
702	if (sc == NULL) {
703		NG_FREE_ITEM(item);
704		return (EHOSTDOWN);
705	}
706	NGI_GET_M(item, m);
707	NG_FREE_ITEM(item);
708
709	/*
710	 * Now queue the data for when it can be sent
711	 */
712	ptag = (void *)m_tag_locate(m, NGM_GENERIC_COOKIE,
713	    NG_TAG_PRIO, NULL);
714
715	if (ptag && (ptag->priority > NG_PRIO_CUTOFF))
716		queue_ptr = &sc->sc_xmitq_hipri;
717	else
718		queue_ptr = &sc->sc_xmitq;
719
720	mtx_lock(&sc->sc_mtx);
721
722	if (NG_BT_MBUFQ_FULL(queue_ptr)) {
723		NG_BT_MBUFQ_DROP(queue_ptr);
724		NG_FREE_M(m);
725		error = ENOBUFS;
726	} else {
727		NG_BT_MBUFQ_ENQUEUE(queue_ptr, m);
728		/*
729		 * start bulk-out transfer, if not already started:
730		 */
731		usb2_transfer_start(sc->sc_xfer[UDBP_T_WR]);
732		error = 0;
733	}
734
735	mtx_unlock(&sc->sc_mtx);
736
737	return (error);
738}
739
740/*
741 * Do local shutdown processing..
742 * We are a persistant device, we refuse to go away, and
743 * only remove our links and reset ourself.
744 */
745static int
746ng_udbp_rmnode(node_p node)
747{
748	struct udbp_softc *sc = NG_NODE_PRIVATE(node);
749
750	/* Let old node go */
751	NG_NODE_SET_PRIVATE(node, NULL);
752	NG_NODE_UNREF(node);		/* forget it ever existed */
753
754	if (sc == NULL) {
755		goto done;
756	}
757	/* Create Netgraph node */
758	if (ng_make_node_common(&ng_udbp_typestruct, &sc->sc_node) != 0) {
759		printf("%s: Could not create Netgraph node\n",
760		    sc->sc_name);
761		sc->sc_node = NULL;
762		goto done;
763	}
764	/* Name node */
765	if (ng_name_node(sc->sc_node, sc->sc_name) != 0) {
766		printf("%s: Could not name Netgraph node\n",
767		    sc->sc_name);
768		NG_NODE_UNREF(sc->sc_node);
769		sc->sc_node = NULL;
770		goto done;
771	}
772	NG_NODE_SET_PRIVATE(sc->sc_node, sc);
773
774done:
775	if (sc) {
776		mtx_unlock(&sc->sc_mtx);
777	}
778	return (0);
779}
780
781/*
782 * This is called once we've already connected a new hook to the other node.
783 * It gives us a chance to balk at the last minute.
784 */
785static int
786ng_udbp_connect(hook_p hook)
787{
788	struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
789
790	/* probably not at splnet, force outward queueing */
791	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
792
793	mtx_lock(&sc->sc_mtx);
794
795	sc->sc_flags |= (UDBP_FLAG_READ_STALL |
796	    UDBP_FLAG_WRITE_STALL);
797
798	/* start bulk-in transfer */
799	usb2_transfer_start(sc->sc_xfer[UDBP_T_RD]);
800
801	/* start bulk-out transfer */
802	usb2_transfer_start(sc->sc_xfer[UDBP_T_WR]);
803
804	mtx_unlock(&sc->sc_mtx);
805
806	return (0);
807}
808
809/*
810 * Dook disconnection
811 *
812 * For this type, removal of the last link destroys the node
813 */
814static int
815ng_udbp_disconnect(hook_p hook)
816{
817	struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
818	int error = 0;
819
820	if (sc != NULL) {
821
822		mtx_lock(&sc->sc_mtx);
823
824		if (hook != sc->sc_hook) {
825			error = EINVAL;
826		} else {
827
828			/* stop bulk-in transfer */
829			usb2_transfer_stop(sc->sc_xfer[UDBP_T_RD_CS]);
830			usb2_transfer_stop(sc->sc_xfer[UDBP_T_RD]);
831
832			/* stop bulk-out transfer */
833			usb2_transfer_stop(sc->sc_xfer[UDBP_T_WR_CS]);
834			usb2_transfer_stop(sc->sc_xfer[UDBP_T_WR]);
835
836			/* cleanup queues */
837			NG_BT_MBUFQ_DRAIN(&sc->sc_xmitq);
838			NG_BT_MBUFQ_DRAIN(&sc->sc_xmitq_hipri);
839
840			if (sc->sc_bulk_in_buffer) {
841				m_freem(sc->sc_bulk_in_buffer);
842				sc->sc_bulk_in_buffer = NULL;
843			}
844			sc->sc_hook = NULL;
845		}
846
847		mtx_unlock(&sc->sc_mtx);
848	}
849	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
850	    && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
851		ng_rmnode_self(NG_HOOK_NODE(hook));
852
853	return (error);
854}
855