From owner-freebsd-current@FreeBSD.ORG Fri Jan 23 22:17:06 2009 Return-Path: Delivered-To: current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 7E3E31065676; Fri, 23 Jan 2009 22:17:06 +0000 (UTC) (envelope-from lars@e.0x20.net) Received: from mail.0x20.net (mail.0x20.net [IPv6:2001:aa8:fffb::3]) by mx1.freebsd.org (Postfix) with ESMTP id 65F768FC14; Fri, 23 Jan 2009 22:17:04 +0000 (UTC) (envelope-from lars@e.0x20.net) Received: by mail.0x20.net (Postfix, from userid 1002) id 5C04F3A6A4; Fri, 23 Jan 2009 23:17:03 +0100 (CET) Date: Fri, 23 Jan 2009 23:17:03 +0100 From: Lars Engels To: Hans Petter Selasky Message-ID: <20090123221703.GR60948@e.0x20.net> Mail-Followup-To: Lars Engels , Hans Petter Selasky , freebsd-current@freebsd.org, Maksim Yevmenkin , current@freebsd.org References: <20090123212952.GM60948@e.0x20.net> <20090123213323.GO60948@e.0x20.net> <200901232249.25153.hselasky@c2i.net> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="Zbynv6TNPa9FrOf6" Content-Disposition: inline In-Reply-To: <200901232249.25153.hselasky@c2i.net> X-Editor: VIM - Vi IMproved 7.1 X-Operation-System: FreeBSD 5.5-RELEASE-p19 User-Agent: mutt-ng/devel-r804 (FreeBSD) Cc: freebsd-current@freebsd.org, current@freebsd.org, Maksim Yevmenkin Subject: Re: [PATCH2] for ng_ubt2 stalled transfers X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Lars Engels List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 23 Jan 2009 22:17:07 -0000 --Zbynv6TNPa9FrOf6 Content-Type: text/plain; charset=iso-8859-15 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Fri, Jan 23, 2009 at 10:49:23PM +0100, Hans Petter Selasky wrote: > On Friday 23 January 2009, Lars Engels wrote: > > I forgot to mention that both bt devices worked without problems with > > the old stack, so there is no hardware issue. :) >=20 > Hi, >=20 > Bluetooth has worked fine with the new USB stack aswell. I have tested th= is=20 > myself. It is just some small problems with the latest changes from Maksi= m=20 > that needs to be ironed out. >=20 > Maybe you can give my patch a try? >=20 > cvsup first >=20 > Then: >=20 > cd /usr/src/sys/dev/usb2/bluetooth; cat bt_patch.diff | patch >=20 > recompile "/usr/src/sys/modules/usb2/bluetooth_ng" module only and test,= =20 > assuming you are loading the module. >=20 > I'm not sure if my patch is 100% correct, Maksim is the bluetooth+Netgrap= h=20 > expert, but at least my bluetooth dongle now works again. >=20 This didn't work too well, the patch did not apply: ng collection src-all/cvs Checkout src/sys/dev/usb2/bluetooth/TODO.TXT Checkout src/sys/dev/usb2/bluetooth/ng_ubt2.c Checkout src/sys/dev/usb2/bluetooth/ng_ubt2_var.h Checkout src/sys/dev/usb2/bluetooth/ubtbcmfw2.c Checkout src/sys/dev/usb2/bluetooth/usb2_bluetooth.c Checkout src/sys/dev/usb2/bluetooth/usb2_bluetooth.h Shutting down connection to server Finished successfully = = Fri, 23. Jan 2009, 23:14:44 = = [maggie:/usr/src/sy= s/dev/usb2/bluetooth] = lars@pts/3 # cat ~/local= -patches/bt_patch.diff | patch Hmm... Looks like a unified diff to me... The text leading up to this was: -------------------------- |diff -u ng_ubt2.c ng_ubt2.c |--- ng_ubt2.c Wed Jan 21 17:51:04 2009 |+++ ng_ubt2.c Fri Jan 23 20:17:44 2009 -------------------------- Patching file ng_ubt2.c using Plan A... Reversed (or previously applied) patch detected! Assume -R? [y] y Hunk #1 succeeded at 28. Hunk #2 failed at 37. Hunk #3 failed at 67. Hunk #4 failed at 111. Hunk #5 succeeded at 163 with fuzz 2 (offset 35 lines). Hunk #6 failed at 314. Hunk #7 failed at 323. Hunk #8 failed at 332. Hunk #9 failed at 341. Hunk #10 failed at 350. Hunk #11 failed at 360. Hunk #12 failed at 373. Hunk #13 failed at 388. Hunk #14 failed at 398. Hunk #15 failed at 408. Hunk #16 failed at 418. Hunk #17 failed at 485. Hunk #18 failed at 518. Hunk #19 failed at 555. Hunk #20 failed at 615. Hunk #21 failed at 629. Hunk #22 failed at 647. Hunk #23 failed at 665. Hunk #24 failed at 692. Hunk #25 succeeded at 825 with fuzz 2 (offset 106 lines). Hunk #26 failed at 846. Hunk #27 failed at 942. Hunk #28 succeeded at 834 with fuzz 2 (offset -21 lines). Hunk #29 failed at 846. Hunk #30 failed at 866. Hunk #31 failed at 962. Hunk #32 succeeded at 980 with fuzz 2 (offset -22 lines). Hunk #33 failed at 992. Hunk #34 failed at 1009. Hunk #35 failed at 1067. Hunk #36 succeeded at 1115 with fuzz 2 (offset 7 lines). Hunk #37 failed at 1127. Hunk #38 succeeded at 1121 with fuzz 2 (offset -16 lines). Hunk #39 failed at 1155. Hunk #40 failed at 1261. Hunk #41 failed at 1289. Hunk #42 failed at 1312. Hunk #43 failed at 1339. Hunk #44 failed at 1530. Hunk #45 failed at 1576. Hunk #46 failed at 1593. Hunk #47 failed at 1602. Hunk #48 failed at 1648. Hunk #49 failed at 1656. Hunk #50 failed at 1807. Hunk #51 failed at 1837. Hunk #52 failed at 1847. Hunk #53 failed at 1865. Hunk #54 failed at 1878. Hunk #55 succeeded at 2235 (offset 273 lines). 47 out of 55 hunks failed--saving rejects to ng_ubt2.c.rej Hmm... The next patch looks like a unified diff to me... The text leading up to this was: -------------------------- |diff -u ng_ubt2_var.h ng_ubt2_var.h |--- ng_ubt2_var.h Wed Jan 21 17:51:04 2009 |+++ ng_ubt2_var.h Fri Jan 23 20:08:04 2009 -------------------------- Patching file ng_ubt2_var.h using Plan A... Reversed (or previously applied) patch detected! Assume -R? [y] y Hunk #1 succeeded at 28. Hunk #2 failed at 47. Hunk #3 failed at 65. Hunk #4 failed at 89. Hunk #5 failed at 100. Hunk #6 failed at 123. 5 out of 6 hunks failed--saving rejects to ng_ubt2_var.h.rej done Exit 52 > diff -u ng_ubt2.c ng_ubt2.c > --- ng_ubt2.c Wed Jan 21 17:51:04 2009 > +++ ng_ubt2.c Fri Jan 23 20:17:44 2009 > @@ -28,7 +28,7 @@ > * SUCH DAMAGE. > * > * $Id: ng_ubt.c,v 1.16 2003/10/10 19:15:06 max Exp $ > - * $FreeBSD$ > + * $FreeBSD: src/sys/dev/usb2/bluetooth/ng_ubt2.c,v 1.6 2009/01/20 23:25= :27 emax Exp $ > */ > =20 > /* > @@ -37,22 +37,12 @@ > * driver will *NOT* create traditional /dev/ enties, only Netgraph=20 > * node. > * > - * NOTE ON LOCKS USED: ng_ubt2 drives uses 3 locks (mutexes) > + * NOTE ON LOCKS USED: ng_ubt2 drives uses 1 lock > * > - * 1) sc_if_mtx[0] - lock for device's interface #0. This lock is used > - * by USB2 for any USB request going over device's interface #0, i.e. > - * interrupt, control and bulk transfers. > - *=20 > - * 2) sc_if_mtx[1] - lock for device's interface #1. This lock is used > - * by USB2 for any USB request going over device's interface #1, i.e > - * isoc. transfers. > - *=20 > - * 3) sc_mbufq_mtx - lock for mbufq and task flags. This lock is used > - * to protect device's outgoing mbuf queues and task flags. This lock > - * *SHOULD NOT* be grabbed for a long time. In fact, think of it as a= =20 > - * spin lock. > + * The "sc_mtx" lock protects both USB and Netgraph data. The "sc_mtx" > + * lock should not be grabbed for a long time. > * > - * NOTE ON LOCKING STRATEGY: ng_ubt2 driver operates in 3 different cont= exts. > + * NOTE ON LOCKING STRATEGY: ng_ubt2 driver operates in 2 different cont= exts. > * > * 1) USB context. This is where all the USB related stuff happens. All > * callbacks run in this context. All callbacks are called (by USB2) = with > @@ -67,26 +57,6 @@ > * grab any long-sleep lock in the Netgraph context. In fact, the only > * lock that is allowed in the Netgraph context is the sc_mbufq_mtx l= ock. > * > - * 3) Taskqueue context. This is where ubt_task runs. Since we are NOT a= llowed > - * to grab any locks in the Netgraph context, and, USB2 requires us to > - * grab interface lock before doing things with transfers, we need to > - * transition from the Netgraph context to the Taskqueue context befo= re > - * we can call into USB2 subsystem. > - * > - * So, to put everything together, the rules are as follows. > - * It is OK to call from the USB context or the Taskqueue context into > - * the Netgraph context (i.e. call NG_SEND_xxx functions). In other words > - * it is allowed to call into the Netgraph context with locks held. > - * Is it *NOT* OK to call from the Netgraph context into the USB context, > - * because USB2 requires us to grab interface locks and we can not do th= at. > - * To avoid this, we set task flags to indicate which actions we want to > - * perform and schedule ubt_task which would run in the Taskqueue contex= t. > - * Is is OK to call from the Taskqueue context into the USB context, > - * and, ubt_task does just that (i.e. grabs appropriate interface locks > - * before calling into USB2). > - * Access to the outgoing queues and task flags is controlled by the > - * sc_mbufq_mtx lock. It is an unavoidable evil. Again, sc_mbufq_mtx sho= uld > - * really be a spin lock. > * All USB callbacks accept Netgraph node pointer as private data. To > * ensure that Netgraph node pointer remains valid for the duration of t= he > * transfer, we grab a referrence to the node. In other words, if transf= er is > @@ -111,7 +81,6 @@ > #include > =20 > #include > -#include > =20 > #include > #include > @@ -128,10 +97,6 @@ > static device_attach_t ubt_attach; > static device_detach_t ubt_detach; > =20 > -static int ubt_task_schedule(ubt_softc_p, int); > -static task_fn_t ubt_task; > -static void ubt_xfer_start(ubt_softc_p, int); > - > /* Netgraph methods */ > static ng_constructor_t ng_ubt_constructor; > static ng_shutdown_t ng_ubt_shutdown; > @@ -279,6 +244,7 @@ > .type =3D UE_BULK, > .endpoint =3D UE_ADDR_ANY, > .direction =3D UE_DIR_OUT, > + .if_index =3D 0, > .mh.bufsize =3D UBT_BULK_WRITE_BUFFER_SIZE, > .mh.flags =3D { .pipe_bof =3D 1, }, > .mh.callback =3D &ubt_bulk_write_callback, > @@ -288,6 +254,7 @@ > .type =3D UE_BULK, > .endpoint =3D UE_ADDR_ANY, > .direction =3D UE_DIR_IN, > + .if_index =3D 0, > .mh.bufsize =3D UBT_BULK_READ_BUFFER_SIZE, > .mh.flags =3D { .pipe_bof =3D 1, .short_xfer_ok =3D 1, }, > .mh.callback =3D &ubt_bulk_read_callback, > @@ -297,6 +264,7 @@ > .type =3D UE_INTERRUPT, > .endpoint =3D UE_ADDR_ANY, > .direction =3D UE_DIR_IN, > + .if_index =3D 0, > .mh.flags =3D { .pipe_bof =3D 1, .short_xfer_ok =3D 1, }, > .mh.bufsize =3D UBT_INTR_BUFFER_SIZE, > .mh.callback =3D &ubt_intr_read_callback, > @@ -306,6 +274,7 @@ > .type =3D UE_CONTROL, > .endpoint =3D 0x00, /* control pipe */ > .direction =3D UE_DIR_ANY, > + .if_index =3D 0, > .mh.bufsize =3D UBT_CTRL_BUFFER_SIZE, > .mh.callback =3D &ubt_ctrl_write_callback, > .mh.timeout =3D 5000, /* 5 seconds */ > @@ -315,6 +284,7 @@ > .type =3D UE_CONTROL, > .endpoint =3D 0x00, /* control pipe */ > .direction =3D UE_DIR_ANY, > + .if_index =3D 0, > .mh.bufsize =3D sizeof(struct usb2_device_request), > .mh.callback =3D &ubt_bulk_write_clear_stall_callback, > .mh.timeout =3D 1000, /* 1 second */ > @@ -325,6 +295,7 @@ > .type =3D UE_CONTROL, > .endpoint =3D 0x00, /* control pipe */ > .direction =3D UE_DIR_ANY, > + .if_index =3D 0, > .mh.bufsize =3D sizeof(struct usb2_device_request), > .mh.callback =3D &ubt_bulk_read_clear_stall_callback, > .mh.timeout =3D 1000, /* 1 second */ > @@ -338,6 +309,7 @@ > .type =3D UE_CONTROL, > .endpoint =3D 0x00, /* control pipe */ > .direction =3D UE_DIR_ANY, > + .if_index =3D 0, > .mh.bufsize =3D sizeof(struct usb2_device_request), > .mh.callback =3D &ubt_intr_read_clear_stall_callback, > .mh.timeout =3D 1000, /* 1 second */ > @@ -353,6 +325,7 @@ > .type =3D UE_ISOCHRONOUS, > .endpoint =3D UE_ADDR_ANY, > .direction =3D UE_DIR_IN, > + .if_index =3D 1, > .mh.bufsize =3D 0, /* use "wMaxPacketSize * frames" */ > .mh.frames =3D UBT_ISOC_NFRAMES, > .mh.flags =3D { .short_xfer_ok =3D 1, }, > @@ -363,6 +336,7 @@ > .type =3D UE_ISOCHRONOUS, > .endpoint =3D UE_ADDR_ANY, > .direction =3D UE_DIR_IN, > + .if_index =3D 1, > .mh.bufsize =3D 0, /* use "wMaxPacketSize * frames" */ > .mh.frames =3D UBT_ISOC_NFRAMES, > .mh.flags =3D { .short_xfer_ok =3D 1, }, > @@ -373,6 +347,7 @@ > .type =3D UE_ISOCHRONOUS, > .endpoint =3D UE_ADDR_ANY, > .direction =3D UE_DIR_OUT, > + .if_index =3D 1, > .mh.bufsize =3D 0, /* use "wMaxPacketSize * frames" */ > .mh.frames =3D UBT_ISOC_NFRAMES, > .mh.flags =3D { .short_xfer_ok =3D 1, }, > @@ -383,6 +358,7 @@ > .type =3D UE_ISOCHRONOUS, > .endpoint =3D UE_ADDR_ANY, > .direction =3D UE_DIR_OUT, > + .if_index =3D 1, > .mh.bufsize =3D 0, /* use "wMaxPacketSize * frames" */ > .mh.frames =3D UBT_ISOC_NFRAMES, > .mh.flags =3D { .short_xfer_ok =3D 1, }, > @@ -450,7 +426,8 @@ > struct ubt_softc *sc =3D device_get_softc(dev); > struct usb2_endpoint_descriptor *ed; > uint16_t wMaxPacketSize; > - uint8_t alt_index, iface_index, i, j; > + uint8_t alt_index, i, j; > + uint8_t iface_index[2]; > =20 > device_set_usb2_desc(dev); > =20 > @@ -483,28 +460,22 @@ > =20 > /* state */ > sc->sc_debug =3D NG_UBT_WARN_LEVEL; > - sc->sc_flags =3D 0; > + > UBT_STAT_RESET(sc); > =20 > /* initialize locks */ > - mtx_init(&sc->sc_mbufq_mtx, "ubt mbufq", NULL, MTX_DEF); > - mtx_init(&sc->sc_if_mtx[0], "ubt if0", NULL, MTX_DEF | MTX_RECURSE); > - mtx_init(&sc->sc_if_mtx[1], "ubt if1", NULL, MTX_DEF | MTX_RECURSE); > + mtx_init(&sc->sc_mtx, "UBT", NULL, MTX_DEF | MTX_RECURSE); > =20 > /* initialize packet queues */ > NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN); > NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN); > NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN); > =20 > - /* initialize glue task */ > - sc->sc_task_flags =3D 0; > - TASK_INIT(&sc->sc_task, 0, ubt_task, sc->sc_node); > - > /* > * Configure Bluetooth USB device. Discover all required USB > * interfaces and endpoints. > * > - * Device is expected to be a high-speed device. > + * Device is expected to be a full-speed device. > * > * USB device must present two interfaces: > * 1) Interface 0 that has 3 endpoints > @@ -520,20 +491,11 @@ > * configurations with different packet size. > */ > =20 > - bzero(&sc->sc_xfer, sizeof(sc->sc_xfer)); > - > /* > * Interface 0 > */ > =20 > - iface_index =3D 0; > - if (usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, > - ubt_config, UBT_IF_0_N_TRANSFER, > - sc->sc_node, &sc->sc_if_mtx[0])) { > - device_printf(dev, "could not allocate transfers for " \ > - "interface 0!\n"); > - goto detach; > - } > + iface_index[0] =3D 0; > =20 > /* > * Interface 1 > @@ -580,13 +542,11 @@ > goto detach; > } > =20 > - iface_index =3D 1; > - if (usb2_transfer_setup(uaa->device, &iface_index, > - &sc->sc_xfer[UBT_IF_0_N_TRANSFER], > - &ubt_config[UBT_IF_0_N_TRANSFER], UBT_IF_1_N_TRANSFER, > - sc->sc_node, &sc->sc_if_mtx[1])) { > - device_printf(dev, "could not allocate transfers for " \ > - "interface 1!\n"); > + iface_index[1] =3D 1; > + if (usb2_transfer_setup(uaa->device, iface_index, > + sc->sc_xfer, ubt_config, UBT_N_TRANSFER, > + sc->sc_node, &sc->sc_mtx)) { > + device_printf(dev, "could not allocate transfers\n"); > goto detach; > } > =20 > @@ -594,6 +554,10 @@ > for (i =3D 1; usb2_get_iface(uaa->device, i) !=3D NULL; i ++) > usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); > =20 > + UBT_LOCK(sc); > + sc->sc_flags |=3D UBT_FLAG_READY; > + UBT_UNLOCK(sc); > + > return (0); /* success */ > =20 > detach: > @@ -612,17 +576,33 @@ > { > struct ubt_softc *sc =3D device_get_softc(dev); > node_p node =3D sc->sc_node; > + uint8_t i; > + > + UBT_LOCK(sc); > + sc->sc_flags &=3D ~UBT_FLAG_READY; > + UBT_UNLOCK(sc); > + > + /* make sure that all USB transfers are stopped! */ > + for (i =3D 0; i !=3D UBT_N_TRANSFER; i++) > + usb2_transfer_drain(sc->sc_xfer[i]); > =20 > /* Destroy Netgraph node */ > if (node !=3D NULL) { > sc->sc_node =3D NULL; > =20 > - NG_NODE_SET_PRIVATE(node, NULL); > NG_NODE_REALLY_DIE(node); > - NG_NODE_REF(node); > ng_rmnode_self(node); > - } > =20 > + /* Need to wait until Netgraph has shutdown the node! */ > + UBT_LOCK(sc); > + while (!(sc->sc_flags & UBT_FLAG_SHUTDOWN)) > + usb2_pause_mtx(&sc->sc_mtx, 100); > + UBT_UNLOCK(sc); > + > + /* Check if there is a leftover hook */ > + if (sc->sc_hook !=3D NULL) > + NG_NODE_UNREF(node); > + } > /* Free USB transfers, if any */ > usb2_transfer_unsetup(sc->sc_xfer, UBT_N_TRANSFER); > =20 > @@ -630,15 +610,13 @@ > NG_NODE_UNREF(node); > =20 > /* Destroy queues */ > - UBT_MBUFQ_LOCK(sc); > + UBT_LOCK(sc); > NG_BT_MBUFQ_DESTROY(&sc->sc_cmdq); > NG_BT_MBUFQ_DESTROY(&sc->sc_aclq); > NG_BT_MBUFQ_DESTROY(&sc->sc_scoq); > - UBT_MBUFQ_UNLOCK(sc); > + UBT_UNLOCK(sc); > =20 > - mtx_destroy(&sc->sc_if_mtx[0]); > - mtx_destroy(&sc->sc_if_mtx[1]); > - mtx_destroy(&sc->sc_mbufq_mtx); > + mtx_destroy(&sc->sc_mtx); > =20 > return (0); > } /* ubt_detach */ > @@ -657,37 +635,25 @@ > struct usb2_device_request req; > struct mbuf *m; > =20 > - if (NG_NODE_NOT_VALID(node)) { > - NG_NODE_UNREF(node); > - return; /* netgraph node is gone */ > - } > - > sc =3D NG_NODE_PRIVATE(node); > =20 > switch (USB_GET_STATE(xfer)) { > case USB_ST_TRANSFERRED: > - if (xfer->error !=3D 0) > - UBT_STAT_OERROR(sc); > - else { > - UBT_INFO(sc, "sent %d bytes to control pipe\n", > - xfer->actlen); > + UBT_INFO(sc, "sent %d bytes to control pipe\n", > + xfer->actlen); > + > + UBT_STAT_BYTES_SENT(sc, xfer->actlen); > + UBT_STAT_PCKTS_SENT(sc); > =20 > - UBT_STAT_BYTES_SENT(sc, xfer->actlen); > - UBT_STAT_PCKTS_SENT(sc); > - } > /* FALLTHROUGH */ > =20 > case USB_ST_SETUP: > send_next: > /* Get next command mbuf, if any */ > - UBT_MBUFQ_LOCK(sc); > NG_BT_MBUFQ_DEQUEUE(&sc->sc_cmdq, m); > - UBT_MBUFQ_UNLOCK(sc); > - > if (m =3D=3D NULL) { > UBT_INFO(sc, "HCI command queue is empty\n"); > - NG_NODE_UNREF(node); > - return; > + break; > } > =20 > /* Initialize a USB control request and then schedule it */ > @@ -719,8 +685,6 @@ > UBT_STAT_OERROR(sc); > goto send_next; > } > - > - NG_NODE_UNREF(node); /* cancelled */ > break; > } > } /* ubt_ctrl_write_callback */ > @@ -740,19 +704,8 @@ > ng_hci_event_pkt_t *hdr; > int error; > =20 > - if (NG_NODE_NOT_VALID(node)) { > - NG_NODE_UNREF(node); > - return; /* netgraph node is gone */ > - } > - > sc =3D NG_NODE_PRIVATE(node); > =20 > - if ((sc->sc_hook =3D=3D NULL) || NG_HOOK_NOT_VALID(sc->sc_hook)) { > - UBT_INFO(sc, "no upstream hook\n"); > - NG_NODE_UNREF(node); > - return; /* upstream hook is gone */ > - } > - > m =3D NULL; > =20 > switch (USB_GET_STATE(xfer)) { > @@ -836,8 +789,7 @@ > /* Try to clear stall first */ > sc->sc_flags |=3D UBT_FLAG_INTR_STALL; > usb2_transfer_start(sc->sc_xfer[UBT_IF_0_INTR_CS_RD]); > - } else > - NG_NODE_UNREF(node); /* cancelled */ > + } > break; > } > } /* ubt_intr_read_callback */ > @@ -855,11 +807,6 @@ > struct ubt_softc *sc; > struct usb2_xfer *xfer_other; > =20 > - if (NG_NODE_NOT_VALID(node)) { > - NG_NODE_UNREF(node); > - return; /* netgraph node is gone */ > - } > - > sc =3D NG_NODE_PRIVATE(node); > xfer_other =3D sc->sc_xfer[UBT_IF_0_INTR_DT_RD]; > =20 > @@ -867,8 +814,7 @@ > DPRINTF("stall cleared\n"); > sc->sc_flags &=3D ~UBT_FLAG_INTR_STALL; > usb2_transfer_start(xfer_other); > - } else > - NG_NODE_UNREF(node); /* cant clear stall */ > + } > } /* ubt_intr_read_clear_stall_callback */ > =20 > /* > @@ -887,19 +833,7 @@ > uint16_t len; > int error; > =20 > - if (NG_NODE_NOT_VALID(node)) { > - NG_NODE_UNREF(node); > - return; /* netgraph node is gone */ > - } > - > sc =3D NG_NODE_PRIVATE(node); > - > - if ((sc->sc_hook =3D=3D NULL) || NG_HOOK_NOT_VALID(sc->sc_hook)) { > - UBT_INFO(sc, "no upstream hook\n"); > - NG_NODE_UNREF(node); > - return; /* upstream hook is gone */ > - } > - > m =3D NULL; > =20 > switch (USB_GET_STATE(xfer)) { > @@ -983,8 +917,7 @@ > /* Try to clear stall first */ > sc->sc_flags |=3D UBT_FLAG_READ_STALL; > usb2_transfer_start(sc->sc_xfer[UBT_IF_0_BULK_CS_RD]); > - } else > - NG_NODE_UNREF(node); /* cancelled */ > + } > break; > } > } /* ubt_bulk_read_callback */ > @@ -1002,11 +935,6 @@ > struct ubt_softc *sc; > struct usb2_xfer *xfer_other; > =20 > - if (NG_NODE_NOT_VALID(node)) { > - NG_NODE_UNREF(node); > - return; /* netgraph node is gone */ > - } > - > sc =3D NG_NODE_PRIVATE(node); > xfer_other =3D sc->sc_xfer[UBT_IF_0_BULK_DT_RD]; > =20 > @@ -1014,8 +942,7 @@ > DPRINTF("stall cleared\n"); > sc->sc_flags &=3D ~UBT_FLAG_READ_STALL; > usb2_transfer_start(xfer_other); > - } else > - NG_NODE_UNREF(node); /* cant clear stall */ > + } > } /* ubt_bulk_read_clear_stall_callback */ > =20 > /* > @@ -1031,36 +958,24 @@ > struct ubt_softc *sc; > struct mbuf *m; > =20 > - if (NG_NODE_NOT_VALID(node)) { > - NG_NODE_UNREF(node); > - return; /* netgraph node is gone */ > - } > - > sc =3D NG_NODE_PRIVATE(node); > =20 > switch (USB_GET_STATE(xfer)) { > case USB_ST_TRANSFERRED: > - if (xfer->error !=3D 0) > - UBT_STAT_OERROR(sc); > - else { > - UBT_INFO(sc, "sent %d bytes to bulk-out pipe\n", > - xfer->actlen); > + UBT_INFO(sc, "sent %d bytes to bulk-out pipe\n", > + xfer->actlen); > + > + UBT_STAT_BYTES_SENT(sc, xfer->actlen); > + UBT_STAT_PCKTS_SENT(sc); > =20 > - UBT_STAT_BYTES_SENT(sc, xfer->actlen); > - UBT_STAT_PCKTS_SENT(sc); > - } > /* FALLTHROUGH */ > =20 > case USB_ST_SETUP: > /* Get next mbuf, if any */ > - UBT_MBUFQ_LOCK(sc); > NG_BT_MBUFQ_DEQUEUE(&sc->sc_aclq, m); > - UBT_MBUFQ_UNLOCK(sc); > - > if (m =3D=3D NULL) { > UBT_INFO(sc, "ACL data queue is empty\n"); > - NG_NODE_UNREF(node); > - return; /* transfer completed */ > + break; > } > =20 > /* > @@ -1089,8 +1004,7 @@ > /* try to clear stall first */ > sc->sc_flags |=3D UBT_FLAG_WRITE_STALL; > usb2_transfer_start(sc->sc_xfer[UBT_IF_0_BULK_CS_WR]); > - } else > - NG_NODE_UNREF(node); /* cancelled */ > + } > break; > } > } /* ubt_bulk_write_callback */ > @@ -1108,11 +1022,6 @@ > struct ubt_softc *sc; > struct usb2_xfer *xfer_other; > =20 > - if (NG_NODE_NOT_VALID(node)) { > - NG_NODE_UNREF(node); > - return; /* netgraph node is gone */ > - } > - > sc =3D NG_NODE_PRIVATE(node); > xfer_other =3D sc->sc_xfer[UBT_IF_0_BULK_DT_WR]; > =20 > @@ -1120,8 +1029,7 @@ > DPRINTF("stall cleared\n"); > sc->sc_flags &=3D ~UBT_FLAG_WRITE_STALL; > usb2_transfer_start(xfer_other); > - } else > - NG_NODE_UNREF(node); /* cant clear stall */ > + } > } /* ubt_bulk_write_clear_stall_callback */ > =20 > /* > @@ -1137,19 +1045,8 @@ > struct ubt_softc *sc; > int n; > =20 > - if (NG_NODE_NOT_VALID(node)) { > - NG_NODE_UNREF(node); > - return; /* netgraph node is gone */ > - } > - > sc =3D NG_NODE_PRIVATE(node); > =20 > - if ((sc->sc_hook =3D=3D NULL) || NG_HOOK_NOT_VALID(sc->sc_hook)) { > - UBT_INFO(sc, "no upstream hook\n"); > - NG_NODE_UNREF(node); > - return; /* upstream hook is gone */ > - } > - > switch (USB_GET_STATE(xfer)) { > case USB_ST_TRANSFERRED: > for (n =3D 0; n < xfer->nframes; n ++) > @@ -1171,8 +1068,6 @@ > goto read_next; > /* NOT REACHED */ > } > - > - NG_NODE_UNREF(node); /* cancelled */ > break; > } > } /* ubt_isoc_read_callback */ > @@ -1277,24 +1172,16 @@ > struct mbuf *m; > int n, space, offset; > =20 > - if (NG_NODE_NOT_VALID(node)) { > - NG_NODE_UNREF(node); > - return; /* netgraph node is gone */ > - } > - > sc =3D NG_NODE_PRIVATE(node); > =20 > switch (USB_GET_STATE(xfer)) { > case USB_ST_TRANSFERRED: > - if (xfer->error) > - UBT_STAT_OERROR(sc); > - else { > - UBT_INFO(sc, "sent %d bytes to isoc-out pipe\n", > - xfer->actlen); > + UBT_INFO(sc, "sent %d bytes to isoc-out pipe\n", > + xfer->actlen); > + > + UBT_STAT_BYTES_SENT(sc, xfer->actlen); > + UBT_STAT_PCKTS_SENT(sc); > =20 > - UBT_STAT_BYTES_SENT(sc, xfer->actlen); > - UBT_STAT_PCKTS_SENT(sc); > - } > /* FALLTHROUGH */ > =20 > case USB_ST_SETUP: > @@ -1305,10 +1192,7 @@ > =20 > while (space > 0) { > if (m =3D=3D NULL) { > - UBT_MBUFQ_LOCK(sc); > NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m); > - UBT_MBUFQ_UNLOCK(sc); > - > if (m =3D=3D NULL) > break; > } > @@ -1328,9 +1212,7 @@ > =20 > /* Put whatever is left from mbuf back on queue */ > if (m !=3D NULL) { > - UBT_MBUFQ_LOCK(sc); > NG_BT_MBUFQ_PREPEND(&sc->sc_scoq, m); > - UBT_MBUFQ_UNLOCK(sc); > } > =20 > /* > @@ -1355,174 +1237,12 @@ > goto send_next; > /* NOT REACHED */ > } > - > - NG_NODE_UNREF(node); /* cancelled */ > break; > } > } > =20 > /***********************************************************************= ***** > ***********************************************************************= ***** > - ** Glue=20 > - ***********************************************************************= ***** > - ***********************************************************************= *****/ > - > -/* > - * Schedule glue task. Should be called with sc_mbufq_mtx held. > - * Netgraph context. > - */ > - > -static int > -ubt_task_schedule(ubt_softc_p sc, int action) > -{ > - mtx_assert(&sc->sc_mbufq_mtx, MA_OWNED); > - > - if ((sc->sc_task_flags & action) =3D=3D 0) { > - /* > - * Try to handle corner case when "start all" and "stop all" > - * actions can both be set before task is executed. > - * > - * Assume the following: > - * 1) "stop all" after "start all" cancels "start all", and, > - * keeps "stop all" > - * > - * 2) "start all" after "stop all" is fine because task is > - * executing "stop all" first > - */ > - > - if (action =3D=3D UBT_FLAG_T_STOP_ALL && > - (sc->sc_task_flags & UBT_FLAG_T_START_ALL) !=3D 0) > - sc->sc_task_flags &=3D ~UBT_FLAG_T_START_ALL; > - > - sc->sc_task_flags |=3D action; > - } > - > - if (sc->sc_task_flags & UBT_FLAG_T_PENDING) > - return (1); > - > - if (taskqueue_enqueue(taskqueue_swi, &sc->sc_task) =3D=3D 0) { > - NG_NODE_REF(sc->sc_node); > - sc->sc_task_flags |=3D UBT_FLAG_T_PENDING; > - return (1); > - } > - > - /* XXX: i think this should never happen */ > - > - return (0); > -} /* ubt_task_schedule */ > - > -/* > - * Glue task. Examines sc_task_flags and does things depending on it. > - * Taskqueue context. > - */ > - > -static void > -ubt_task(void *context, int pending) > -{ > - node_p node =3D context; > - ubt_softc_p sc; > - int task_flags; > - > - if (NG_NODE_NOT_VALID(node)) { > - NG_NODE_UNREF(node); > - return; /* netgraph node is gone */ > - } > - > - sc =3D NG_NODE_PRIVATE(node); > - > - UBT_MBUFQ_LOCK(sc); > - task_flags =3D sc->sc_task_flags; > - sc->sc_task_flags =3D 0; > - UBT_MBUFQ_UNLOCK(sc); > - > - /* Stop all USB transfers */ > - if (task_flags & UBT_FLAG_T_STOP_ALL) { > - int i; > - > - /* > - * Interface #0 > - */ > - > - mtx_lock(&sc->sc_if_mtx[0]); > - > - for (i =3D UBT_IF_0_BULK_DT_WR; i < UBT_IF_0_N_TRANSFER; i ++) > - usb2_transfer_stop(sc->sc_xfer[i]); > - > - mtx_unlock(&sc->sc_if_mtx[0]); > - > - /* > - * Interface #1 > - */ > - > - mtx_lock(&sc->sc_if_mtx[1]); > - > - for (i =3D UBT_IF_1_ISOC_DT_RD1; i < UBT_N_TRANSFER; i ++)=20 > - usb2_transfer_stop(sc->sc_xfer[i]); > - > - mtx_unlock(&sc->sc_if_mtx[1]); > - } > - > - /* Start all incoming USB transfers */ > - if (task_flags & UBT_FLAG_T_START_ALL) { > - /* > - * Interface #0 > - */ > - > - mtx_lock(&sc->sc_if_mtx[0]); > - ubt_xfer_start(sc, UBT_IF_0_INTR_DT_RD); > - ubt_xfer_start(sc, UBT_IF_0_BULK_DT_RD); > - mtx_unlock(&sc->sc_if_mtx[0]); > - > - /* > - * Interface #1 > - * Start both read and write isoc. transfers by default. > - * Get them going all the time even if we have nothing > - * to send to avoid any delays. > - */ > - > - mtx_lock(&sc->sc_if_mtx[1]); > - ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD1); > - ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD2); > - ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR1); > - ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR2); > - mtx_unlock(&sc->sc_if_mtx[1]); > - } > - > - /* Start outgoing control transfer */ > - if (task_flags & UBT_FLAG_T_START_CTRL) { > - mtx_lock(&sc->sc_if_mtx[0]); > - ubt_xfer_start(sc, UBT_IF_0_CTRL_DT_WR); > - mtx_unlock(&sc->sc_if_mtx[0]); > - } > - > - /* Start outgoing bulk transfer */ > - if (task_flags & UBT_FLAG_T_START_BULK) { > - mtx_lock(&sc->sc_if_mtx[0]); > - ubt_xfer_start(sc, UBT_IF_0_BULK_DT_WR); > - mtx_unlock(&sc->sc_if_mtx[0]); > - } > - > - NG_NODE_UNREF(node); > -} /* ubt_task */ > - > -/* > - * Start USB transfer. > - * Helper function called from ubt_task. Must be called with appropriate > - * interface lock held. > - * Taskqueue context. > - */ > - > -static void > -ubt_xfer_start(ubt_softc_p sc, int transfer) > -{ > - if (!usb2_transfer_pending(sc->sc_xfer[transfer])) { > - NG_NODE_REF(sc->sc_node); > - usb2_transfer_start(sc->sc_xfer[transfer]); > - } > -} /* ubt_xfer_start */ > - > -/***********************************************************************= ***** > - ***********************************************************************= ***** > ** Netgraph specific > ***********************************************************************= ***** > ***********************************************************************= *****/ > @@ -1546,13 +1266,18 @@ > static int > ng_ubt_shutdown(node_p node) > { > + struct ubt_softc *sc =3D NG_NODE_PRIVATE(node); > + > if (node->nd_flags & NGF_REALLY_DIE) { > /* > * We came here because the USB device is being > * detached, so stop being persistant. > */ > + UBT_LOCK(sc); > + sc->sc_flags |=3D UBT_FLAG_SHUTDOWN; > + UBT_UNLOCK(sc); > + > NG_NODE_SET_PRIVATE(node, NULL); > - NG_NODE_UNREF(node); > } else > NG_NODE_REVIVE(node); /* tell ng_rmnode we are persisant */ > =20 > @@ -1592,9 +1317,21 @@ > =20 > NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); > =20 > - UBT_MBUFQ_LOCK(sc); > - ubt_task_schedule(sc, UBT_FLAG_T_START_ALL); > - UBT_MBUFQ_UNLOCK(sc); > + if (!(sc->sc_flags & UBT_FLAG_READY)) { > + /* called too early */ > + return (EINVAL); > + } > + > + NG_NODE_REF(sc->sc_node); > + > + UBT_LOCK(sc); > + usb2_transfer_start(sc->sc_xfer[UBT_IF_0_INTR_DT_RD]); > + usb2_transfer_start(sc->sc_xfer[UBT_IF_0_BULK_DT_RD]); > + usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_RD1]); > + usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_RD2]); > + usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_WR1]); > + usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_WR2]); > + UBT_UNLOCK(sc); > =20 > return (0); > } /* ng_ubt_connect */ > @@ -1609,6 +1346,7 @@ > { > node_p node =3D NG_HOOK_NODE(hook); > struct ubt_softc *sc; > + uint8_t i; > =20 > if (NG_NODE_NOT_VALID(node)) > return (0); > @@ -1618,19 +1356,25 @@ > if (hook !=3D sc->sc_hook) > return (EINVAL); > =20 > + /*=20 > + * Synchronously drain all USB transfers: > + * Can take some milliseconds! > + */ > + for (i =3D 0; i !=3D UBT_N_TRANSFER; i++) > + usb2_transfer_drain(sc->sc_xfer[i]); > + > sc->sc_hook =3D NULL; > =20 > - UBT_MBUFQ_LOCK(sc); > + UBT_LOCK(sc); > =20 > /* Drain queues */ > NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq); > NG_BT_MBUFQ_DRAIN(&sc->sc_aclq); > NG_BT_MBUFQ_DRAIN(&sc->sc_scoq); > =20 > - /* Kick off task to stop all USB xfers */ > - ubt_task_schedule(sc, UBT_FLAG_T_STOP_ALL); > + UBT_UNLOCK(sc); > =20 > - UBT_MBUFQ_UNLOCK(sc); > + NG_NODE_UNREF(node); > =20 > return (0); > } /* ng_ubt_disconnect */ > @@ -1664,7 +1408,6 @@ > "Refs: %d\n" \ > "Hook: %s\n" \ > "Flags: %#x\n" \ > - "Task flags: %#x\n" \ > "Debug: %d\n" \ > "CMD queue: [have:%d,max:%d]\n" \ > "ACL queue: [have:%d,max:%d]\n" \ > @@ -1672,7 +1415,6 @@ > node->nd_refs, > (sc->sc_hook !=3D NULL) ? NG_UBT_HOOK:"", > sc->sc_flags, > - sc->sc_task_flags, > sc->sc_debug, > sc->sc_cmdq.len, > sc->sc_cmdq.maxlen, > @@ -1823,7 +1565,8 @@ > struct ubt_softc *sc =3D NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); > struct mbuf *m; > struct ng_bt_mbufq *q; > - int action, error =3D 0; > + int error =3D 0; > + uint8_t xfer_action; > =20 > if (hook !=3D sc->sc_hook) { > error =3D EINVAL; > @@ -1853,7 +1596,7 @@ > UBT_CTRL_BUFFER_SIZE, m->m_pkthdr.len); > =20 > q =3D &sc->sc_cmdq; > - action =3D UBT_FLAG_T_START_CTRL; > + xfer_action =3D UBT_IF_0_CTRL_DT_WR; > break; > =20 > case NG_HCI_ACL_DATA_PKT: > @@ -1863,12 +1606,12 @@ > UBT_BULK_WRITE_BUFFER_SIZE, m->m_pkthdr.len); > =20 > q =3D &sc->sc_aclq; > - action =3D UBT_FLAG_T_START_BULK; > + xfer_action =3D UBT_IF_0_BULK_DT_WR; > break; > =20 > case NG_HCI_SCO_DATA_PKT: > q =3D &sc->sc_scoq; > - action =3D 0; > + xfer_action =3D 255; > break; > =20 > default: > @@ -1881,10 +1624,10 @@ > /* NOT REACHED */ > } > =20 > - UBT_MBUFQ_LOCK(sc); > + UBT_LOCK(sc); > if (NG_BT_MBUFQ_FULL(q)) { > NG_BT_MBUFQ_DROP(q); > - UBT_MBUFQ_UNLOCK(sc); > + UBT_UNLOCK(sc); > =09 > UBT_ERR(sc, "Dropping HCI frame 0x%02x, len=3D%d. Queue full\n", > *mtod(m, uint8_t *), m->m_pkthdr.len); > @@ -1894,9 +1637,9 @@ > /* Loose HCI packet type, enqueue mbuf and kick off task */ > m_adj(m, sizeof(uint8_t)); > NG_BT_MBUFQ_ENQUEUE(q, m); > - ubt_task_schedule(sc, action); > - > - UBT_MBUFQ_UNLOCK(sc); > + if (xfer_action !=3D 255) > + usb2_transfer_start(sc->sc_xfer[xfer_action]); > + UBT_UNLOCK(sc); > } > done: > NG_FREE_ITEM(item); > @@ -1962,4 +1705,3 @@ > MODULE_DEPEND(ng_ubt, ng_hci, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION= , NG_BLUETOOTH_VERSION); > MODULE_DEPEND(ng_ubt, usb2_bluetooth, 1, 1, 1); > MODULE_DEPEND(ng_ubt, usb2_core, 1, 1, 1); > - > diff -u ng_ubt2_var.h ng_ubt2_var.h > --- ng_ubt2_var.h Wed Jan 21 17:51:04 2009 > +++ ng_ubt2_var.h Fri Jan 23 20:08:04 2009 > @@ -28,7 +28,7 @@ > * SUCH DAMAGE. > * > * $Id: ng_ubt_var.h,v 1.2 2003/03/22 23:44:36 max Exp $ > - * $FreeBSD$ > + * $FreeBSD: src/sys/dev/usb2/bluetooth/ng_ubt2_var.h,v 1.2 2009/01/20 2= 2:17:05 emax Exp $ > */ > =20 > #ifndef _NG_UBT_VAR_H_ > @@ -47,8 +47,8 @@ > #define UBT_WARN(...) UBT_DEBUG(NG_UBT_WARN_LEVEL, __VA_ARGS__) > #define UBT_INFO(...) UBT_DEBUG(NG_UBT_INFO_LEVEL, __VA_ARGS__) > =20 > -#define UBT_MBUFQ_LOCK(sc) mtx_lock(&(sc)->sc_mbufq_mtx) > -#define UBT_MBUFQ_UNLOCK(sc) mtx_unlock(&(sc)->sc_mbufq_mtx) > +#define UBT_LOCK(sc) mtx_lock(&(sc)->sc_mtx) > +#define UBT_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) > =20 > /* Bluetooth USB control request type */ > #define UBT_HCI_REQUEST 0x20 > @@ -65,17 +65,14 @@ > UBT_IF_0_BULK_CS_WR, > UBT_IF_0_BULK_CS_RD, > UBT_IF_0_INTR_CS_RD, > - UBT_IF_0_N_TRANSFER, /* number of interface 0's transfers */ > =09 > /* Interface #1 transfers */ > - UBT_IF_1_ISOC_DT_RD1 =3D UBT_IF_0_N_TRANSFER, > + UBT_IF_1_ISOC_DT_RD1, > UBT_IF_1_ISOC_DT_RD2, > UBT_IF_1_ISOC_DT_WR1, > UBT_IF_1_ISOC_DT_WR2, > =20 > UBT_N_TRANSFER, /* total number of transfers */ > - > - UBT_IF_1_N_TRANSFER =3D UBT_N_TRANSFER - UBT_IF_1_ISOC_DT_RD1, > }; > =20 > /* USB device softc structure */ > @@ -89,6 +86,8 @@ > #define UBT_FLAG_READ_STALL (1 << 0) /* read transfer has stalled */ > #define UBT_FLAG_WRITE_STALL (1 << 1) /* write transfer has stalled */ > #define UBT_FLAG_INTR_STALL (1 << 2) /* inter transfer has stalled */ > +#define UBT_FLAG_READY (1 << 4) /* set when we are ready */ > +#define UBT_FLAG_SHUTDOWN (1 << 5) /* set when we are shutdown */ > =20 > ng_ubt_node_stat_ep sc_stat; /* statistic */ > #define UBT_STAT_PCKTS_SENT(sc) (sc)->sc_stat.pckts_sent ++ > @@ -100,11 +99,9 @@ > #define UBT_STAT_RESET(sc) bzero(&(sc)->sc_stat, sizeof((sc)->sc_stat)) > =20 > /* USB device specific */ > - struct mtx sc_if_mtx[2]; /* interface locks */ > + struct mtx sc_mtx; > struct usb2_xfer *sc_xfer[UBT_N_TRANSFER]; > =20 > - struct mtx sc_mbufq_mtx; /* lock for all queues */ > - > /* HCI commands */ > struct ng_bt_mbufq sc_cmdq; /* HCI command queue */ > #define UBT_CTRL_BUFFER_SIZE (sizeof(struct usb2_device_request) + \ > @@ -123,17 +120,6 @@ > /* Netgraph specific */ > node_p sc_node; /* pointer back to node */ > hook_p sc_hook; /* upstream hook */ > - > - /* Glue */ > - int sc_task_flags; /* task flags */ > -#define UBT_FLAG_T_PENDING (1 << 0) /* task pending */ > -#define UBT_FLAG_T_STOP_ALL (1 << 1) /* stop all xfers */ > -#define UBT_FLAG_T_START_ALL (1 << 2) /* start all read and isoc > - write xfers */ > -#define UBT_FLAG_T_START_CTRL (1 << 3) /* start control xfer (write) */ > -#define UBT_FLAG_T_START_BULK (1 << 4) /* start bulk xfer (write) */ > - > - struct task sc_task; > }; > typedef struct ubt_softc ubt_softc_t; > typedef struct ubt_softc * ubt_softc_p; --=20 Lars Engels E-Mail: lars.engels@0x20.net =09 --Zbynv6TNPa9FrOf6 Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (FreeBSD) iEYEARECAAYFAkl6Qd8ACgkQKc512sD3afjbZwCgjF1ln3UHqXH4MHL2MG5Hnf6f 030AnjJJDtNP4PcHcFyWo48ypWf+qH5t =xthe -----END PGP SIGNATURE----- --Zbynv6TNPa9FrOf6--