xref: /freebsd/sys/dev/usb/misc/udbp.c (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1996-2000 Whistle Communications, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of author nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY NICK HIBMA AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 #include <sys/cdefs.h>
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 /* probe/attach/detach:
45  *  Connect the driver to the hardware and netgraph
46  *
47  *  The reason we submit a bulk in transfer is that USB does not know about
48  *  interrupts. The bulk transfer continuously polls the device for data.
49  *  While the device has no data available, the device NAKs the TDs. As soon
50  *  as there is data, the transfer happens and the data comes flowing in.
51  *
52  *  In case you were wondering, interrupt transfers happen exactly that way.
53  *  It therefore doesn't make sense to use the interrupt pipe to signal
54  *  'data ready' and then schedule a bulk transfer to fetch it. That would
55  *  incur a 2ms delay at least, without reducing bandwidth requirements.
56  *
57  */
58 
59 #include <sys/stdint.h>
60 #include <sys/stddef.h>
61 #include <sys/param.h>
62 #include <sys/queue.h>
63 #include <sys/types.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/bus.h>
67 #include <sys/module.h>
68 #include <sys/lock.h>
69 #include <sys/mutex.h>
70 #include <sys/condvar.h>
71 #include <sys/sysctl.h>
72 #include <sys/sx.h>
73 #include <sys/unistd.h>
74 #include <sys/callout.h>
75 #include <sys/malloc.h>
76 #include <sys/priv.h>
77 
78 #include <dev/usb/usb.h>
79 #include <dev/usb/usbdi.h>
80 #include <dev/usb/usbdi_util.h>
81 #include "usbdevs.h"
82 
83 #define	USB_DEBUG_VAR udbp_debug
84 #include <dev/usb/usb_debug.h>
85 
86 #include <sys/mbuf.h>
87 
88 #include <netgraph/ng_message.h>
89 #include <netgraph/netgraph.h>
90 #include <netgraph/ng_parse.h>
91 #include <netgraph/bluetooth/include/ng_bluetooth.h>
92 
93 #include <dev/usb/misc/udbp.h>
94 
95 #ifdef USB_DEBUG
96 static int udbp_debug = 0;
97 
98 static SYSCTL_NODE(_hw_usb, OID_AUTO, udbp, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
99     "USB udbp");
100 SYSCTL_INT(_hw_usb_udbp, OID_AUTO, debug, CTLFLAG_RWTUN,
101     &udbp_debug, 0, "udbp debug level");
102 #endif
103 
104 #define	UDBP_TIMEOUT	2000		/* timeout on outbound transfers, in
105 					 * msecs */
106 #define	UDBP_BUFFERSIZE	MCLBYTES	/* maximum number of bytes in one
107 					 * transfer */
108 #define	UDBP_T_WR       0
109 #define	UDBP_T_RD       1
110 #define	UDBP_T_WR_CS    2
111 #define	UDBP_T_RD_CS    3
112 #define	UDBP_T_MAX      4
113 #define	UDBP_Q_MAXLEN   50
114 
115 struct udbp_softc {
116 	struct mtx sc_mtx;
117 	struct ng_bt_mbufq sc_xmitq_hipri;	/* hi-priority transmit queue */
118 	struct ng_bt_mbufq sc_xmitq;	/* low-priority transmit queue */
119 
120 	struct usb_xfer *sc_xfer[UDBP_T_MAX];
121 	node_p	sc_node;		/* back pointer to node */
122 	hook_p	sc_hook;		/* pointer to the hook */
123 	struct mbuf *sc_bulk_in_buffer;
124 
125 	uint32_t sc_packets_in;		/* packets in from downstream */
126 	uint32_t sc_packets_out;	/* packets out towards downstream */
127 
128 	uint8_t	sc_flags;
129 #define	UDBP_FLAG_READ_STALL    0x01	/* read transfer stalled */
130 #define	UDBP_FLAG_WRITE_STALL   0x02	/* write transfer stalled */
131 
132 	uint8_t	sc_name[16];
133 };
134 
135 /* prototypes */
136 
137 static int udbp_modload(module_t mod, int event, void *data);
138 
139 static device_probe_t udbp_probe;
140 static device_attach_t udbp_attach;
141 static device_detach_t udbp_detach;
142 
143 static usb_callback_t udbp_bulk_read_callback;
144 static usb_callback_t udbp_bulk_read_clear_stall_callback;
145 static usb_callback_t udbp_bulk_write_callback;
146 static usb_callback_t udbp_bulk_write_clear_stall_callback;
147 
148 static void	udbp_bulk_read_complete(node_p, hook_p, void *, int);
149 
150 static ng_constructor_t	ng_udbp_constructor;
151 static ng_rcvmsg_t	ng_udbp_rcvmsg;
152 static ng_shutdown_t	ng_udbp_rmnode;
153 static ng_newhook_t	ng_udbp_newhook;
154 static ng_connect_t	ng_udbp_connect;
155 static ng_rcvdata_t	ng_udbp_rcvdata;
156 static ng_disconnect_t	ng_udbp_disconnect;
157 
158 /* Parse type for struct ngudbpstat */
159 static const struct ng_parse_struct_field
160 	ng_udbp_stat_type_fields[] = NG_UDBP_STATS_TYPE_INFO;
161 
162 static const struct ng_parse_type ng_udbp_stat_type = {
163 	&ng_parse_struct_type,
164 	&ng_udbp_stat_type_fields
165 };
166 
167 /* List of commands and how to convert arguments to/from ASCII */
168 static const struct ng_cmdlist ng_udbp_cmdlist[] = {
169 	{
170 		NGM_UDBP_COOKIE,
171 		NGM_UDBP_GET_STATUS,
172 		"getstatus",
173 		NULL,
174 		&ng_udbp_stat_type,
175 	},
176 	{
177 		NGM_UDBP_COOKIE,
178 		NGM_UDBP_SET_FLAG,
179 		"setflag",
180 		&ng_parse_int32_type,
181 		NULL
182 	},
183 	{0}
184 };
185 
186 /* Netgraph node type descriptor */
187 static struct ng_type ng_udbp_typestruct = {
188 	.version = NG_ABI_VERSION,
189 	.name = NG_UDBP_NODE_TYPE,
190 	.constructor = ng_udbp_constructor,
191 	.rcvmsg = ng_udbp_rcvmsg,
192 	.shutdown = ng_udbp_rmnode,
193 	.newhook = ng_udbp_newhook,
194 	.connect = ng_udbp_connect,
195 	.rcvdata = ng_udbp_rcvdata,
196 	.disconnect = ng_udbp_disconnect,
197 	.cmdlist = ng_udbp_cmdlist,
198 };
199 
200 /* USB config */
201 static const struct usb_config udbp_config[UDBP_T_MAX] = {
202 	[UDBP_T_WR] = {
203 		.type = UE_BULK,
204 		.endpoint = UE_ADDR_ANY,
205 		.direction = UE_DIR_OUT,
206 		.bufsize = UDBP_BUFFERSIZE,
207 		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
208 		.callback = &udbp_bulk_write_callback,
209 		.timeout = UDBP_TIMEOUT,
210 	},
211 
212 	[UDBP_T_RD] = {
213 		.type = UE_BULK,
214 		.endpoint = UE_ADDR_ANY,
215 		.direction = UE_DIR_IN,
216 		.bufsize = UDBP_BUFFERSIZE,
217 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
218 		.callback = &udbp_bulk_read_callback,
219 	},
220 
221 	[UDBP_T_WR_CS] = {
222 		.type = UE_CONTROL,
223 		.endpoint = 0x00,	/* Control pipe */
224 		.direction = UE_DIR_ANY,
225 		.bufsize = sizeof(struct usb_device_request),
226 		.callback = &udbp_bulk_write_clear_stall_callback,
227 		.timeout = 1000,	/* 1 second */
228 		.interval = 50,	/* 50ms */
229 	},
230 
231 	[UDBP_T_RD_CS] = {
232 		.type = UE_CONTROL,
233 		.endpoint = 0x00,	/* Control pipe */
234 		.direction = UE_DIR_ANY,
235 		.bufsize = sizeof(struct usb_device_request),
236 		.callback = &udbp_bulk_read_clear_stall_callback,
237 		.timeout = 1000,	/* 1 second */
238 		.interval = 50,	/* 50ms */
239 	},
240 };
241 
242 static device_method_t udbp_methods[] = {
243 	/* Device interface */
244 	DEVMETHOD(device_probe, udbp_probe),
245 	DEVMETHOD(device_attach, udbp_attach),
246 	DEVMETHOD(device_detach, udbp_detach),
247 
248 	DEVMETHOD_END
249 };
250 
251 static driver_t udbp_driver = {
252 	.name = "udbp",
253 	.methods = udbp_methods,
254 	.size = sizeof(struct udbp_softc),
255 };
256 
257 static const STRUCT_USB_HOST_ID udbp_devs[] = {
258 	{USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U258, 0)},
259 	{USB_VPI(USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_TURBOCONNECT, 0)},
260 	{USB_VPI(USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_GADGETZERO, 0)},
261 	{USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2301, 0)},
262 	{USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2302, 0)},
263 	{USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL27A1, 0)},
264 	{USB_VPI(USB_VENDOR_ANCHOR, USB_PRODUCT_ANCHOR_EZLINK, 0)},
265 	{USB_VPI(USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL620USB, 0)},
266 };
267 
268 DRIVER_MODULE(udbp, uhub, udbp_driver, udbp_modload, NULL);
269 MODULE_DEPEND(udbp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
270 MODULE_DEPEND(udbp, usb, 1, 1, 1);
271 MODULE_VERSION(udbp, 1);
272 USB_PNP_HOST_INFO(udbp_devs);
273 
274 static int
275 udbp_modload(module_t mod, int event, void *data)
276 {
277 	int error;
278 
279 	switch (event) {
280 	case MOD_LOAD:
281 		error = ng_newtype(&ng_udbp_typestruct);
282 		if (error != 0) {
283 			printf("%s: Could not register "
284 			    "Netgraph node type, error=%d\n",
285 			    NG_UDBP_NODE_TYPE, error);
286 		}
287 		break;
288 
289 	case MOD_UNLOAD:
290 		error = ng_rmtype(&ng_udbp_typestruct);
291 		break;
292 
293 	default:
294 		error = EOPNOTSUPP;
295 		break;
296 	}
297 	return (error);
298 }
299 
300 static int
301 udbp_probe(device_t dev)
302 {
303 	struct usb_attach_arg *uaa = device_get_ivars(dev);
304 
305 	if (uaa->usb_mode != USB_MODE_HOST)
306 		return (ENXIO);
307 	if (uaa->info.bConfigIndex != 0)
308 		return (ENXIO);
309 	if (uaa->info.bIfaceIndex != 0)
310 		return (ENXIO);
311 
312 	return (usbd_lookup_id_by_uaa(udbp_devs, sizeof(udbp_devs), uaa));
313 }
314 
315 static int
316 udbp_attach(device_t dev)
317 {
318 	struct usb_attach_arg *uaa = device_get_ivars(dev);
319 	struct udbp_softc *sc = device_get_softc(dev);
320 	int error;
321 
322 	device_set_usb_desc(dev);
323 
324 	snprintf(sc->sc_name, sizeof(sc->sc_name),
325 	    "%s", device_get_nameunit(dev));
326 
327 	mtx_init(&sc->sc_mtx, "udbp lock", NULL, MTX_DEF | MTX_RECURSE);
328 
329 	error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
330 	    sc->sc_xfer, udbp_config, UDBP_T_MAX, sc, &sc->sc_mtx);
331 	if (error) {
332 		DPRINTF("error=%s\n", usbd_errstr(error));
333 		goto detach;
334 	}
335 	NG_BT_MBUFQ_INIT(&sc->sc_xmitq, UDBP_Q_MAXLEN);
336 
337 	NG_BT_MBUFQ_INIT(&sc->sc_xmitq_hipri, UDBP_Q_MAXLEN);
338 
339 	/* create Netgraph node */
340 
341 	if (ng_make_node_common(&ng_udbp_typestruct, &sc->sc_node) != 0) {
342 		printf("%s: Could not create Netgraph node\n",
343 		    sc->sc_name);
344 		sc->sc_node = NULL;
345 		goto detach;
346 	}
347 	/* name node */
348 
349 	if (ng_name_node(sc->sc_node, sc->sc_name) != 0) {
350 		printf("%s: Could not name node\n",
351 		    sc->sc_name);
352 		NG_NODE_UNREF(sc->sc_node);
353 		sc->sc_node = NULL;
354 		goto detach;
355 	}
356 	NG_NODE_SET_PRIVATE(sc->sc_node, sc);
357 
358 	/* the device is now operational */
359 
360 	return (0);			/* success */
361 
362 detach:
363 	udbp_detach(dev);
364 	return (ENOMEM);		/* failure */
365 }
366 
367 static int
368 udbp_detach(device_t dev)
369 {
370 	struct udbp_softc *sc = device_get_softc(dev);
371 
372 	/* destroy Netgraph node */
373 
374 	if (sc->sc_node != NULL) {
375 		NG_NODE_SET_PRIVATE(sc->sc_node, NULL);
376 		ng_rmnode_self(sc->sc_node);
377 		sc->sc_node = NULL;
378 	}
379 	/* free USB transfers, if any */
380 
381 	usbd_transfer_unsetup(sc->sc_xfer, UDBP_T_MAX);
382 
383 	mtx_destroy(&sc->sc_mtx);
384 
385 	/* destroy queues */
386 
387 	NG_BT_MBUFQ_DESTROY(&sc->sc_xmitq);
388 	NG_BT_MBUFQ_DESTROY(&sc->sc_xmitq_hipri);
389 
390 	/* extra check */
391 
392 	if (sc->sc_bulk_in_buffer) {
393 		m_freem(sc->sc_bulk_in_buffer);
394 		sc->sc_bulk_in_buffer = NULL;
395 	}
396 	return (0);			/* success */
397 }
398 
399 static void
400 udbp_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
401 {
402 	struct udbp_softc *sc = usbd_xfer_softc(xfer);
403 	struct usb_page_cache *pc;
404 	struct mbuf *m;
405 	int actlen;
406 
407 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
408 
409 	switch (USB_GET_STATE(xfer)) {
410 	case USB_ST_TRANSFERRED:
411 
412 		/* allocate new mbuf */
413 
414 		MGETHDR(m, M_NOWAIT, MT_DATA);
415 
416 		if (m == NULL) {
417 			goto tr_setup;
418 		}
419 
420 		if (!(MCLGET(m, M_NOWAIT))) {
421 			m_freem(m);
422 			goto tr_setup;
423 		}
424 		m->m_pkthdr.len = m->m_len = actlen;
425 
426 		pc = usbd_xfer_get_frame(xfer, 0);
427 		usbd_copy_out(pc, 0, m->m_data, actlen);
428 
429 		sc->sc_bulk_in_buffer = m;
430 
431 		DPRINTF("received package %d bytes\n", actlen);
432 
433 	case USB_ST_SETUP:
434 tr_setup:
435 		if (sc->sc_bulk_in_buffer) {
436 			ng_send_fn(sc->sc_node, NULL, &udbp_bulk_read_complete, NULL, 0);
437 			return;
438 		}
439 		if (sc->sc_flags & UDBP_FLAG_READ_STALL) {
440 			usbd_transfer_start(sc->sc_xfer[UDBP_T_RD_CS]);
441 			return;
442 		}
443 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
444 		usbd_transfer_submit(xfer);
445 		return;
446 
447 	default:			/* Error */
448 		if (error != USB_ERR_CANCELLED) {
449 			/* try to clear stall first */
450 			sc->sc_flags |= UDBP_FLAG_READ_STALL;
451 			usbd_transfer_start(sc->sc_xfer[UDBP_T_RD_CS]);
452 		}
453 		return;
454 	}
455 }
456 
457 static void
458 udbp_bulk_read_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
459 {
460 	struct udbp_softc *sc = usbd_xfer_softc(xfer);
461 	struct usb_xfer *xfer_other = sc->sc_xfer[UDBP_T_RD];
462 
463 	if (usbd_clear_stall_callback(xfer, xfer_other)) {
464 		DPRINTF("stall cleared\n");
465 		sc->sc_flags &= ~UDBP_FLAG_READ_STALL;
466 		usbd_transfer_start(xfer_other);
467 	}
468 }
469 
470 static void
471 udbp_bulk_read_complete(node_p node, hook_p hook, void *arg1, int arg2)
472 {
473 	struct udbp_softc *sc = NG_NODE_PRIVATE(node);
474 	struct mbuf *m;
475 	int error;
476 
477 	if (sc == NULL) {
478 		return;
479 	}
480 	mtx_lock(&sc->sc_mtx);
481 
482 	m = sc->sc_bulk_in_buffer;
483 
484 	if (m) {
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 	}
498 done:
499 	if (m) {
500 		m_freem(m);
501 	}
502 	/* start USB bulk-in transfer, if not already started */
503 
504 	usbd_transfer_start(sc->sc_xfer[UDBP_T_RD]);
505 
506 	mtx_unlock(&sc->sc_mtx);
507 }
508 
509 static void
510 udbp_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
511 {
512 	struct udbp_softc *sc = usbd_xfer_softc(xfer);
513 	struct usb_page_cache *pc;
514 	struct mbuf *m;
515 
516 	switch (USB_GET_STATE(xfer)) {
517 	case USB_ST_TRANSFERRED:
518 
519 		sc->sc_packets_out++;
520 
521 	case USB_ST_SETUP:
522 		if (sc->sc_flags & UDBP_FLAG_WRITE_STALL) {
523 			usbd_transfer_start(sc->sc_xfer[UDBP_T_WR_CS]);
524 			return;
525 		}
526 		/* get next mbuf, if any */
527 
528 		NG_BT_MBUFQ_DEQUEUE(&sc->sc_xmitq_hipri, m);
529 		if (m == NULL) {
530 			NG_BT_MBUFQ_DEQUEUE(&sc->sc_xmitq, m);
531 			if (m == NULL) {
532 				DPRINTF("Data queue is empty\n");
533 				return;
534 			}
535 		}
536 		if (m->m_pkthdr.len > MCLBYTES) {
537 			DPRINTF("truncating large packet "
538 			    "from %d to %d bytes\n", m->m_pkthdr.len,
539 			    MCLBYTES);
540 			m->m_pkthdr.len = MCLBYTES;
541 		}
542 		pc = usbd_xfer_get_frame(xfer, 0);
543 		usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
544 
545 		usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
546 
547 		DPRINTF("packet out: %d bytes\n", m->m_pkthdr.len);
548 
549 		m_freem(m);
550 
551 		usbd_transfer_submit(xfer);
552 		return;
553 
554 	default:			/* Error */
555 		if (error != USB_ERR_CANCELLED) {
556 			/* try to clear stall first */
557 			sc->sc_flags |= UDBP_FLAG_WRITE_STALL;
558 			usbd_transfer_start(sc->sc_xfer[UDBP_T_WR_CS]);
559 		}
560 		return;
561 	}
562 }
563 
564 static void
565 udbp_bulk_write_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
566 {
567 	struct udbp_softc *sc = usbd_xfer_softc(xfer);
568 	struct usb_xfer *xfer_other = sc->sc_xfer[UDBP_T_WR];
569 
570 	if (usbd_clear_stall_callback(xfer, xfer_other)) {
571 		DPRINTF("stall cleared\n");
572 		sc->sc_flags &= ~UDBP_FLAG_WRITE_STALL;
573 		usbd_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  */
586 static int
587 ng_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  */
603 static int
604 ng_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  */
637 static int
638 ng_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  */
693 static int
694 ng_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 		usbd_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 persistent device, we refuse to go away, and
743  * only remove our links and reset ourself.
744  */
745 static int
746 ng_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 
774 done:
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  */
785 static int
786 ng_udbp_connect(hook_p hook)
787 {
788 	struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
789 
790 	/* 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 	usbd_transfer_start(sc->sc_xfer[UDBP_T_RD]);
800 
801 	/* start bulk-out transfer */
802 	usbd_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  */
814 static int
815 ng_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 		mtx_lock(&sc->sc_mtx);
822 
823 		if (hook != sc->sc_hook) {
824 			error = EINVAL;
825 		} else {
826 			/* stop bulk-in transfer */
827 			usbd_transfer_stop(sc->sc_xfer[UDBP_T_RD_CS]);
828 			usbd_transfer_stop(sc->sc_xfer[UDBP_T_RD]);
829 
830 			/* stop bulk-out transfer */
831 			usbd_transfer_stop(sc->sc_xfer[UDBP_T_WR_CS]);
832 			usbd_transfer_stop(sc->sc_xfer[UDBP_T_WR]);
833 
834 			/* cleanup queues */
835 			NG_BT_MBUFQ_DRAIN(&sc->sc_xmitq);
836 			NG_BT_MBUFQ_DRAIN(&sc->sc_xmitq_hipri);
837 
838 			if (sc->sc_bulk_in_buffer) {
839 				m_freem(sc->sc_bulk_in_buffer);
840 				sc->sc_bulk_in_buffer = NULL;
841 			}
842 			sc->sc_hook = NULL;
843 		}
844 
845 		mtx_unlock(&sc->sc_mtx);
846 	}
847 	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
848 	    && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
849 		ng_rmnode_self(NG_HOOK_NODE(hook));
850 
851 	return (error);
852 }
853