Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Call for testing of ehci(4), ohci(4), slhci(4), uhci(4) data toggle patch



On 2010-04-27, Yorick Hardy wrote:
> On 2010-04-27, Matthias Drochner wrote:
> > 
> > yorickhardy%gmail.com@localhost said:
> > > Can you try the patch below?
> > 
> > I didn't test yet, but wouldn't it look better to avoid the
> > array which will be used only sparsely, and use some
> > linked list or so instead? The per-device bitfield could be
> > put into something device-specific, perhaps close to
> > the default control pipe.
> 
> Yes, I had thought to do that. I was looking for an easy
> solution to make sure that all problems are resolved first.
> 
> Perhaps the best place is in struct usbd_device?
> Storing the toggle status here may be misleading
> since for example uhci and ehci update the toggle
> after transferring a number of packets, not
> necessarily for each one, and ohci would only update
> the toggle status on closing a pipe (assuming the
> last patch is correct).

Perhaps something like this?

-- 
Kind regards,

Yorick Hardy

Index: sys/dev/ic/sl811hs.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/sl811hs.c,v
retrieving revision 1.25
diff -u -r1.25 sl811hs.c
--- sys/dev/ic/sl811hs.c        25 Nov 2009 14:28:50 -0000      1.25
+++ sys/dev/ic/sl811hs.c        27 Apr 2010 20:18:12 -0000
@@ -282,7 +282,6 @@
        struct gcq      xq;             /* Xfer queues */
        unsigned int    pflags;         /* Pipe flags */
 #define PF_GONE                (0x01)          /* Pipe is on disabled device */
-#define PF_TOGGLE      (0x02)          /* Data toggle status */
 #define PF_LS          (0x04)          /* Pipe is low speed */
 #define PF_PREAMBLE    (0x08)          /* Needs preamble */
        Frame           to_frame;       /* Frame number for timeout */
@@ -433,6 +432,7 @@
 void slhci_freem(struct usbd_bus *, usb_dma_t *);
 struct usbd_xfer * slhci_allocx(struct usbd_bus *);
 void slhci_freex(struct usbd_bus *, struct usbd_xfer *);
+void slhci_clear_all_toggle(struct usbd_bus *, struct usbd_device *);
 
 usbd_status slhci_transfer(struct usbd_xfer *);
 usbd_status slhci_start(struct usbd_xfer *);
@@ -685,6 +685,7 @@
        slhci_freem,
        slhci_allocx,
        slhci_freex,
+       slhci_clear_all_toggle,
 };
 
 const struct usbd_pipe_methods slhci_pipe_methods = {
@@ -849,6 +850,11 @@
        free(xfer, M_USB);
 }
 
+void slhci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
+{
+       dev->toggle = 0;
+}
+
 usbd_status
 slhci_transfer(struct usbd_xfer *xfer)
 {
@@ -923,7 +929,7 @@
        spipe->newlen[1] = min(xfer->length, max_packet);
 
        if (spipe->ptype == PT_BULK || spipe->ptype == PT_INTR) {
-               if (spipe->pflags & PF_TOGGLE)
+               if (USBD_PIPE_TOGGLE_ISSET(&(spipe->pipe)))
                        spipe->control |= SL11_EPCTRL_DATATOGGLE;
                spipe->tregs[LEN] = spipe->newlen[1];
                if (spipe->tregs[LEN]) 
@@ -1291,7 +1297,7 @@
        DLOG(D_TRACE, "%s toggle spipe %p", pnames(spipe->ptype), 
            spipe,0,0);
 
-       spipe->pflags &= ~PF_TOGGLE;
+       USBD_PIPE_TOGGLE_CLR(&(spipe->pipe));
 
 #ifdef DIAGNOSTIC
        if (spipe->xfer != NULL) {
@@ -2140,9 +2146,9 @@
                         * current setting will apply to the next 
                         * transfer. */ 
                        if (spipe->control & SL11_EPCTRL_DATATOGGLE)
-                               spipe->pflags |= PF_TOGGLE;
+                               USBD_PIPE_TOGGLE_SET(&(spipe->pipe));
                        else
-                               spipe->pflags &= ~PF_TOGGLE;
+                               USBD_PIPE_TOGGLE_CLR(&(spipe->pipe));
 
                        head = Q_CALLBACKS;
                }
Index: sys/dev/usb/ehci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ehci.c,v
retrieving revision 1.166
diff -u -r1.166 ehci.c
--- sys/dev/usb/ehci.c  24 Feb 2010 22:38:09 -0000      1.166
+++ sys/dev/usb/ehci.c  27 Apr 2010 20:18:21 -0000
@@ -91,7 +91,6 @@
 
 struct ehci_pipe {
        struct usbd_pipe pipe;
-       int nexttoggle;
 
        ehci_soft_qh_t *sqh;
        union {
@@ -139,6 +138,9 @@
 Static usbd_xfer_handle        ehci_allocx(struct usbd_bus *);
 Static void            ehci_freex(struct usbd_bus *, usbd_xfer_handle);
 
+Static void            ehci_clear_all_toggle(struct usbd_bus *,
+                                               struct usbd_device *);
+
 Static usbd_status     ehci_root_ctrl_transfer(usbd_xfer_handle);
 Static usbd_status     ehci_root_ctrl_start(usbd_xfer_handle);
 Static void            ehci_root_ctrl_abort(usbd_xfer_handle);
@@ -252,6 +254,7 @@
        ehci_freem,
        ehci_allocx,
        ehci_freex,
+       ehci_clear_all_toggle,
 };
 
 Static const struct usbd_pipe_methods ehci_root_ctrl_methods = {
@@ -953,7 +956,10 @@
                ehci_dump_sqh(epipe->sqh);
                ehci_dump_sqtds(ex->sqtdstart);
 #endif
-               epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(nstatus);
+               if (EHCI_QTD_GET_TOGGLE(nstatus))
+                       USBD_PIPE_TOGGLE_SET(&(epipe->pipe));
+               else
+                       USBD_PIPE_TOGGLE_CLR(&(epipe->pipe));
        }
 
        DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n",
@@ -1318,6 +1324,12 @@
 }
 
 Static void
+ehci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
+{
+       dev->toggle = 0;
+}
+
+Static void
 ehci_device_clear_toggle(usbd_pipe_handle pipe)
 {
        struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
@@ -1328,7 +1340,7 @@
        if (ehcidebug)
                usbd_dump_pipe(pipe);
 #endif
-       epipe->nexttoggle = 0;
+       USBD_PIPE_TOGGLE_CLR(&(epipe->pipe));
 }
 
 Static void
@@ -1549,8 +1561,6 @@
        if (sc->sc_dying)
                return (USBD_IOERROR);
 
-       epipe->nexttoggle = 0;
-
        if (addr == sc->sc_addr) {
                switch (ed->bEndpointAddress) {
                case USB_CONTROL_ENDPOINT:
@@ -2597,7 +2607,7 @@
            /* BYTES set below */
            ;
        mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize);
-       tog = epipe->nexttoggle;
+       tog = USBD_PIPE_TOGGLE_GET(&(epipe->pipe));
        qtdstatus |= EHCI_QTD_SET_TOGGLE(tog);
 
        cur = ehci_alloc_sqtd(sc);
@@ -2702,7 +2712,10 @@
        usb_syncmem(&cur->dma, cur->offs, sizeof(cur->qtd),
            BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        *ep = cur;
-       epipe->nexttoggle = tog;
+       if (tog)
+               USBD_PIPE_TOGGLE_SET(&(epipe->pipe));
+       else
+               USBD_PIPE_TOGGLE_CLR(&(epipe->pipe));
 
        DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n",
                     *sp, *ep));
@@ -2846,9 +2859,11 @@
        ehci_soft_qtd_t *sqtd;
        ehci_physaddr_t cur;
        u_int32_t qhstatus;
+       u_int32_t nstatus;
        int s;
        int hit;
        int wake;
+       int fixdt;
 
        DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));
 
@@ -2902,11 +2917,21 @@
            sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status),
            sizeof(sqh->qh.qh_qtd.qtd_status),
            BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-       for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) {
+       for (sqtd = exfer->sqtdstart, fixdt = 1; ; sqtd = sqtd->nextqtd) {
                usb_syncmem(&sqtd->dma,
                    sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
                    sizeof(sqtd->qtd.qtd_status),
                    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+               nstatus = le32toh(sqtd->qtd.qtd_status);
+               if (fixdt && (nstatus & EHCI_QTD_ACTIVE)
+                         && ((sqtd != exfer->sqtdend->nextqtd)
+                             || EHCI_QTD_GET_BYTES(nstatus))) {
+                       if (EHCI_QTD_GET_TOGGLE(nstatus))
+                               USBD_PIPE_TOGGLE_SET(&(epipe->pipe));
+                       else
+                               USBD_PIPE_TOGGLE_CLR(&(epipe->pipe));
+                       fixdt = 0;
+               }
                sqtd->qtd.qtd_status |= htole32(EHCI_QTD_HALTED);
                usb_syncmem(&sqtd->dma,
                    sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
@@ -3260,7 +3285,7 @@
                ehci_soft_qtd_t *end;
 
                /* Start toggle at 1. */
-               epipe->nexttoggle = 1;
+               USBD_PIPE_TOGGLE_SET(&(epipe->pipe));
                err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
                          &next, &end);
                if (err)
Index: sys/dev/usb/ohci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ohci.c,v
retrieving revision 1.206
diff -u -r1.206 ohci.c
--- sys/dev/usb/ohci.c  24 Feb 2010 22:38:09 -0000      1.206
+++ sys/dev/usb/ohci.c  27 Apr 2010 20:18:27 -0000
@@ -134,6 +134,9 @@
 Static usbd_xfer_handle        ohci_allocx(struct usbd_bus *);
 Static void            ohci_freex(struct usbd_bus *, usbd_xfer_handle);
 
+Static void            ohci_clear_all_toggle(struct usbd_bus *,
+                                               struct usbd_device *);
+
 Static usbd_status     ohci_root_ctrl_transfer(usbd_xfer_handle);
 Static usbd_status     ohci_root_ctrl_start(usbd_xfer_handle);
 Static void            ohci_root_ctrl_abort(usbd_xfer_handle);
@@ -273,6 +276,7 @@
        ohci_freem,
        ohci_allocx,
        ohci_freex,
+       ohci_clear_all_toggle,
 };
 
 Static const struct usbd_pipe_methods ohci_root_ctrl_methods = {
@@ -983,6 +987,19 @@
        SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
 }
 
+Static void
+ohci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
+{
+       struct ohci_softc *sc = bus->hci_private;
+       struct ohci_soft_ed *ed = sc->sc_bulk_head;
+       while (ed != NULL) {
+               if (OHCI_ED_GET_FA(ed->ed.ed_flags) == dev->address)
+                       ed->ed.ed_headp &= HTOO32(~OHCI_TOGGLECARRY);
+               ed = ed->next;
+       }
+       dev->toggle = 0;
+}
+
 /*
  * Shut down the controller when the system is going down.
  */
@@ -2119,6 +2136,8 @@
                        fmt |
                        OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize)));
                sed->ed.ed_headp = sed->ed.ed_tailp = HTOO32(tdphys);
+               if (USBD_PIPE_TOGGLE_ISSET(&(opipe->pipe)))
+                       sed->ed.ed_headp |= HTOO32(OHCI_TOGGLECARRY);
                usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed),
                    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 
@@ -2206,6 +2225,10 @@
        /* Make sure the host controller is not touching this ED */
        usb_delay_ms(&sc->sc_bus, 1);
        splx(s);
+       if (opipe->sed->ed.ed_headp & HTOO32(OHCI_TOGGLECARRY))
+               USBD_PIPE_TOGGLE_SET(&(opipe->pipe));
+       else
+               USBD_PIPE_TOGGLE_CLR(&(opipe->pipe));
        ohci_free_sed(sc, opipe->sed);
 }
 
@@ -3194,6 +3217,10 @@
                --sc->sc_bws[(pos * nslots + j) % OHCI_NO_INTRS];
 
        ohci_free_std(sc, opipe->tail.td);
+       if (opipe->sed->ed.ed_headp & HTOO32(OHCI_TOGGLECARRY))
+               USBD_PIPE_TOGGLE_SET(&(opipe->pipe));
+       else
+               USBD_PIPE_TOGGLE_CLR(&(opipe->pipe));
        ohci_free_sed(sc, opipe->sed);
 }
 
Index: sys/dev/usb/uhci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/uhci.c,v
retrieving revision 1.232
diff -u -r1.232 uhci.c
--- sys/dev/usb/uhci.c  24 Feb 2010 22:38:09 -0000      1.232
+++ sys/dev/usb/uhci.c  27 Apr 2010 20:18:33 -0000
@@ -91,7 +91,6 @@
 
 struct uhci_pipe {
        struct usbd_pipe pipe;
-       int nexttoggle;
 
        u_char aborting;
        usbd_xfer_handle abortstart, abortend;
@@ -171,6 +170,9 @@
 Static usbd_xfer_handle        uhci_allocx(struct usbd_bus *);
 Static void            uhci_freex(struct usbd_bus *, usbd_xfer_handle);
 
+Static void            uhci_clear_all_toggle(struct usbd_bus *,
+                                               struct usbd_device *);
+
 Static usbd_status     uhci_device_ctrl_transfer(usbd_xfer_handle);
 Static usbd_status     uhci_device_ctrl_start(usbd_xfer_handle);
 Static void            uhci_device_ctrl_abort(usbd_xfer_handle);
@@ -287,6 +289,7 @@
        uhci_freem,
        uhci_allocx,
        uhci_freex,
+       uhci_clear_all_toggle,
 };
 
 const struct usbd_pipe_methods uhci_root_ctrl_methods = {
@@ -683,6 +686,12 @@
        SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
 }
 
+Static void
+uhci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
+{
+       dev->toggle = 0;
+}
+
 /*
  * Handle suspend/resume.
  *
@@ -1564,8 +1573,12 @@
                }
        }
        /* If there are left over TDs we need to update the toggle. */
-       if (std != NULL)
-               upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token));
+       if (std != NULL) {
+               if (UHCI_TD_GET_DT(le32toh(std->td.td_token)))
+                       USBD_PIPE_TOGGLE_SET(&(upipe->pipe));
+               else
+                       USBD_PIPE_TOGGLE_CLR(&(upipe->pipe));
+       }
 
        status &= UHCI_TD_ERROR;
        DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n",
@@ -1884,10 +1897,13 @@
                DPRINTFN(-1,("uhci_alloc_std_chain: ntd=0\n"));
                return (USBD_NORMAL_COMPLETION);
        }
-       tog = upipe->nexttoggle;
+       tog = USBD_PIPE_TOGGLE_GET(&(upipe->pipe));
        if (ntd % 2 == 0)
                tog ^= 1;
-       upipe->nexttoggle = tog ^ 1;
+       if (tog ^ 1)
+               USBD_PIPE_TOGGLE_SET(&(upipe->pipe));
+       else
+               USBD_PIPE_TOGGLE_CLR(&(upipe->pipe));
        lastp = NULL;
        lastlink = UHCI_PTR_T;
        ntd--;
@@ -1928,7 +1944,7 @@
        }
        *sp = lastp;
        DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n",
-                     upipe->nexttoggle));
+                     USBD_PIPE_TOGGLE_GET(&(upipe->pipe))));
        return (USBD_NORMAL_COMPLETION);
 }
 
@@ -1936,7 +1952,7 @@
 uhci_device_clear_toggle(usbd_pipe_handle pipe)
 {
        struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
-       upipe->nexttoggle = 0;
+       USBD_PIPE_TOGGLE_CLR(&(upipe->pipe));
 }
 
 void
@@ -2077,6 +2093,7 @@
        uhci_soft_td_t *std;
        int s;
        int wake;
+       int fixdt;
 
        DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
 
@@ -2120,11 +2137,18 @@
        xfer->status = status;  /* make software ignore it */
        usb_uncallout(xfer->timeout_handle, uhci_timeout, ii);
        DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii));
-       for (std = ii->stdstart; std != NULL; std = std->link.std) {
+       for (std = ii->stdstart, fixdt = 1; std != NULL; std = std->link.std) {
                usb_syncmem(&std->dma,
                    std->offs + offsetof(uhci_td_t, td_status),
                    sizeof(std->td.td_status),
                    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+               if (fixdt && (le32toh(std->td.td_status) & UHCI_TD_ACTIVE)) {
+                       if (UHCI_TD_GET_DT(le32toh(std->td.td_token)))
+                               USBD_PIPE_TOGGLE_SET(&(upipe->pipe));
+                       else
+                               USBD_PIPE_TOGGLE_CLR(&(upipe->pipe));
+                       fixdt = 0;
+               }
                std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
                usb_syncmem(&std->dma,
                    std->offs + offsetof(uhci_td_t, td_status),
@@ -2409,7 +2433,7 @@
 
        /* Set up data transaction */
        if (len != 0) {
-               upipe->nexttoggle = 1;
+               USBD_PIPE_TOGGLE_SET(&(upipe->pipe));
                err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags,
                                           &xfer->dmabuf, &data, &dataend);
                if (err)
@@ -3183,7 +3207,6 @@
                     ed->bEndpointAddress, sc->sc_addr));
 
        upipe->aborting = 0;
-       upipe->nexttoggle = 0;
 
        if (pipe->device->address == sc->sc_addr) {
                switch (ed->bEndpointAddress) {
Index: sys/dev/usb/usb_subr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usb_subr.c,v
retrieving revision 1.167
diff -u -r1.167 usb_subr.c
--- sys/dev/usb/usb_subr.c      12 Nov 2009 20:11:35 -0000      1.167
+++ sys/dev/usb/usb_subr.c      27 Apr 2010 20:18:47 -0000
@@ -698,6 +698,9 @@
                }
        }
 
+       /* this is a configuration event, so reset all data toggles */
+       dev->bus->methods->clear_all_toggle(dev->bus, dev);
+
        return (USBD_NORMAL_COMPLETION);
 
  bad:
Index: sys/dev/usb/usbdi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usbdi.c,v
retrieving revision 1.127
diff -u -r1.127 usbdi.c
--- sys/dev/usb/usbdi.c 16 Jan 2010 17:03:03 -0000      1.127
+++ sys/dev/usb/usbdi.c 27 Apr 2010 20:19:07 -0000
@@ -669,7 +669,14 @@
        USETW(req.wValue, iface->idesc->bAlternateSetting);
        USETW(req.wIndex, iface->idesc->bInterfaceNumber);
        USETW(req.wLength, 0);
-       return (usbd_do_request(iface->device, &req, 0));
+       err = usbd_do_request(iface->device, &req, 0);
+
+       /* this is a configuration event, so reset all data toggles */
+       if (!err)
+               iface->device->bus->methods
+                       ->clear_all_toggle(iface->device->bus, iface->device);
+
+       return err;
 }
 
 int
Index: sys/dev/usb/usbdivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usbdivar.h,v
retrieving revision 1.91
diff -u -r1.91 usbdivar.h
--- sys/dev/usb/usbdivar.h      12 Nov 2009 20:11:35 -0000      1.91
+++ sys/dev/usb/usbdivar.h      27 Apr 2010 20:19:08 -0000
@@ -57,6 +57,8 @@
        void                  (*freem)(struct usbd_bus *, usb_dma_t *);
        struct usbd_xfer *    (*allocx)(struct usbd_bus *);
        void                  (*freex)(struct usbd_bus *, struct usbd_xfer *);
+       void                  (*clear_all_toggle)(struct usbd_bus *,
+                                                       struct usbd_device *);
 };
 
 struct usbd_pipe_methods {
@@ -148,6 +150,14 @@
        int                     subdevlen;     /* array length of following */
        device_t               *subdevs;       /* sub-devices */
        int                     nifaces_claimed; /* number of ifaces in use */
+       /*
+        * data toggles for each endpoint
+        * Note: The HCI drivers update the toggles, so the value may not
+        *       reflect the hardware toggle state, but rather the last toggle
+        *       state required for the HCI driver to perform the next
+        *       transaction successfully.
+        */
+       u_int32_t               toggle;
 };
 
 struct usbd_interface {
@@ -178,6 +188,23 @@
        const struct usbd_pipe_methods *methods;
 };
 
+#define USBD_PIPE_TOGGLE(pipe) (pipe)->device->toggle
+#define USBD_PIPE_ENDPOINT_ADDR(pipe) \
+       UE_GET_ADDR((pipe)->endpoint->edesc->bEndpointAddress)
+#define USBD_PIPE_ENDPOINT_DIR(pipe) \
+       UE_GET_DIR((pipe)->endpoint->edesc->bEndpointAddress)
+#define USBD_PIPE_TOGGLE_BIT(pipe) \
+               ((USBD_PIPE_ENDPOINT_DIR(pipe) == UE_DIR_OUT) ? \
+                       (0x00000001 << USBD_PIPE_ENDPOINT_ADDR(pipe)) : \
+                       (0x00010000 << USBD_PIPE_ENDPOINT_ADDR(pipe)))
+#define USBD_PIPE_TOGGLE_SET(pipe) \
+               SET(USBD_PIPE_TOGGLE(pipe), USBD_PIPE_TOGGLE_BIT(pipe))
+#define USBD_PIPE_TOGGLE_ISSET(pipe) \
+               ISSET(USBD_PIPE_TOGGLE(pipe), USBD_PIPE_TOGGLE_BIT(pipe))
+#define USBD_PIPE_TOGGLE_GET(pipe) ((USBD_PIPE_TOGGLE_ISSET(pipe))?1:0)
+#define USBD_PIPE_TOGGLE_CLR(pipe) \
+               CLR(USBD_PIPE_TOGGLE(pipe), USBD_PIPE_TOGGLE_BIT(pipe))
+
 struct usbd_xfer {
        struct usbd_pipe       *pipe;
        void                   *priv;


Home | Main Index | Thread Index | Old Index