Author: thompsa
Date: Fri Mar 20 21:57:54 2009
New Revision: 190183
URL: http://svn.freebsd.org/changeset/base/190183

Log:
  MFp4 //depot/projects/usb @159479,159502,159516,159522,159529
  
  Workaround for buggy USB hardware not handling new SETUP packet before STATUS
  stage is complete, this allows xfers to endpoint0 to return a short frame.
  
  Submitted by: Hans Petter Selasky
  Reported by:  me

Modified:
  head/sys/dev/usb/controller/at91dci.c
  head/sys/dev/usb/controller/at91dci_atmelarm.c
  head/sys/dev/usb/controller/atmegadci.c
  head/sys/dev/usb/controller/atmegadci_atmelarm.c
  head/sys/dev/usb/controller/ehci.c
  head/sys/dev/usb/controller/ehci_ixp4xx.c
  head/sys/dev/usb/controller/ehci_mbus.c
  head/sys/dev/usb/controller/ehci_pci.c
  head/sys/dev/usb/controller/musb_otg.c
  head/sys/dev/usb/controller/musb_otg_atmelarm.c
  head/sys/dev/usb/controller/ohci.c
  head/sys/dev/usb/controller/ohci_atmelarm.c
  head/sys/dev/usb/controller/ohci_pci.c
  head/sys/dev/usb/controller/uhci.c
  head/sys/dev/usb/controller/uhci_pci.c
  head/sys/dev/usb/controller/uss820dci.c
  head/sys/dev/usb/controller/uss820dci_atmelarm.c

Modified: head/sys/dev/usb/controller/at91dci.c
==============================================================================
--- head/sys/dev/usb/controller/at91dci.c       Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/at91dci.c       Fri Mar 20 21:57:54 2009        
(r190183)
@@ -887,8 +887,8 @@ at91dci_setup_standard_chain(struct usb2
 
        temp.td = NULL;
        temp.td_next = xfer->td_start[0];
-       temp.setup_alt_next = xfer->flags_int.short_frames_ok;
        temp.offset = 0;
+       temp.setup_alt_next = xfer->flags_int.short_frames_ok;
 
        sc = AT9100_DCI_BUS2SC(xfer->xroot->bus);
        ep_no = (xfer->endpoint & UE_ADDR);
@@ -902,6 +902,12 @@ at91dci_setup_standard_chain(struct usb2
                        temp.len = xfer->frlengths[0];
                        temp.pc = xfer->frbuffers + 0;
                        temp.short_pkt = temp.len ? 1 : 0;
+                       /* check for last frame */
+                       if (xfer->nframes == 1) {
+                               /* no STATUS stage yet, SETUP is last */
+                               if (xfer->flags_int.control_act)
+                                       temp.setup_alt_next = 0;
+                       }
 
                        at91dci_setup_standard_chain_sub(&temp);
                }
@@ -933,7 +939,13 @@ at91dci_setup_standard_chain(struct usb2
                x++;
 
                if (x == xfer->nframes) {
-                       temp.setup_alt_next = 0;
+                       if (xfer->flags_int.control_xfr) {
+                               if (xfer->flags_int.control_act) {
+                                       temp.setup_alt_next = 0;
+                               }
+                       } else {
+                               temp.setup_alt_next = 0;
+                       }
                }
                if (temp.len == 0) {
 
@@ -958,47 +970,46 @@ at91dci_setup_standard_chain(struct usb2
                }
        }
 
-       /* always setup a valid "pc" pointer for status and sync */
-       temp.pc = xfer->frbuffers + 0;
-
-       /* check if we need to sync */
-       if (need_sync && xfer->flags_int.control_xfr) {
-
-               /* we need a SYNC point after TX */
-               temp.func = &at91dci_data_tx_sync;
-               temp.len = 0;
-               temp.short_pkt = 0;
-
-               at91dci_setup_standard_chain_sub(&temp);
-       }
-       /* check if we should append a status stage */
-       if (xfer->flags_int.control_xfr &&
-           !xfer->flags_int.control_act) {
+       /* check for control transfer */
+       if (xfer->flags_int.control_xfr) {
 
-               /*
-                * Send a DATA1 message and invert the current
-                * endpoint direction.
-                */
-               if (xfer->endpoint & UE_DIR_IN) {
-                       temp.func = &at91dci_data_rx;
-                       need_sync = 0;
-               } else {
-                       temp.func = &at91dci_data_tx;
-                       need_sync = 1;
-               }
+               /* always setup a valid "pc" pointer for status and sync */
+               temp.pc = xfer->frbuffers + 0;
                temp.len = 0;
                temp.short_pkt = 0;
+               temp.setup_alt_next = 0;
 
-               at91dci_setup_standard_chain_sub(&temp);
+               /* check if we need to sync */
                if (need_sync) {
                        /* we need a SYNC point after TX */
                        temp.func = &at91dci_data_tx_sync;
-                       temp.len = 0;
-                       temp.short_pkt = 0;
+                       at91dci_setup_standard_chain_sub(&temp);
+               }
+
+               /* check if we should append a status stage */
+               if (!xfer->flags_int.control_act) {
+
+                       /*
+                        * Send a DATA1 message and invert the current
+                        * endpoint direction.
+                        */
+                       if (xfer->endpoint & UE_DIR_IN) {
+                               temp.func = &at91dci_data_rx;
+                               need_sync = 0;
+                       } else {
+                               temp.func = &at91dci_data_tx;
+                               need_sync = 1;
+                       }
 
                        at91dci_setup_standard_chain_sub(&temp);
+                       if (need_sync) {
+                               /* we need a SYNC point after TX */
+                               temp.func = &at91dci_data_tx_sync;
+                               at91dci_setup_standard_chain_sub(&temp);
+                       }
                }
        }
+
        /* must have at least one frame! */
        td = temp.td;
        xfer->td_transfer_last = td;

Modified: head/sys/dev/usb/controller/at91dci_atmelarm.c
==============================================================================
--- head/sys/dev/usb/controller/at91dci_atmelarm.c      Fri Mar 20 21:51:27 
2009        (r190182)
+++ head/sys/dev/usb/controller/at91dci_atmelarm.c      Fri Mar 20 21:57:54 
2009        (r190183)
@@ -204,10 +204,10 @@ at91_udp_attach(device_t dev)
 
 #if (__FreeBSD_version >= 700031)
        err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | 
INTR_MPSAFE,
-           NULL, (void *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl);
+           NULL, (driver_intr_t *)at91dci_interrupt, sc, 
&sc->sc_dci.sc_intr_hdl);
 #else
        err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | 
INTR_MPSAFE,
-           (void *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl);
+           (driver_intr_t *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl);
 #endif
        if (err) {
                sc->sc_dci.sc_intr_hdl = NULL;
@@ -215,10 +215,10 @@ at91_udp_attach(device_t dev)
        }
 #if (__FreeBSD_version >= 700031)
        err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | 
INTR_MPSAFE,
-           NULL, (void *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl);
+           NULL, (driver_intr_t *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl);
 #else
        err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | 
INTR_MPSAFE,
-           (void *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl);
+           (driver_intr_t *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl);
 #endif
        if (err) {
                sc->sc_vbus_intr_hdl = NULL;

Modified: head/sys/dev/usb/controller/atmegadci.c
==============================================================================
--- head/sys/dev/usb/controller/atmegadci.c     Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/atmegadci.c     Fri Mar 20 21:57:54 2009        
(r190183)
@@ -791,8 +791,8 @@ atmegadci_setup_standard_chain(struct us
 
        temp.td = NULL;
        temp.td_next = xfer->td_start[0];
-       temp.setup_alt_next = xfer->flags_int.short_frames_ok;
        temp.offset = 0;
+       temp.setup_alt_next = xfer->flags_int.short_frames_ok;
 
        sc = ATMEGA_BUS2SC(xfer->xroot->bus);
        ep_no = (xfer->endpoint & UE_ADDR);
@@ -806,6 +806,12 @@ atmegadci_setup_standard_chain(struct us
                        temp.len = xfer->frlengths[0];
                        temp.pc = xfer->frbuffers + 0;
                        temp.short_pkt = temp.len ? 1 : 0;
+                       /* check for last frame */
+                       if (xfer->nframes == 1) {
+                               /* no STATUS stage yet, SETUP is last */
+                               if (xfer->flags_int.control_act)
+                                       temp.setup_alt_next = 0;
+                       }
 
                        atmegadci_setup_standard_chain_sub(&temp);
                }
@@ -837,7 +843,13 @@ atmegadci_setup_standard_chain(struct us
                x++;
 
                if (x == xfer->nframes) {
-                       temp.setup_alt_next = 0;
+                       if (xfer->flags_int.control_xfr) {
+                               if (xfer->flags_int.control_act) {
+                                       temp.setup_alt_next = 0;
+                               }
+                       } else {
+                               temp.setup_alt_next = 0;
+                       }
                }
                if (temp.len == 0) {
 
@@ -862,45 +874,42 @@ atmegadci_setup_standard_chain(struct us
                }
        }
 
-       /* always setup a valid "pc" pointer for status and sync */
-       temp.pc = xfer->frbuffers + 0;
-
-       /* check if we need to sync */
-       if (need_sync && xfer->flags_int.control_xfr) {
+       if (xfer->flags_int.control_xfr) {
 
-               /* we need a SYNC point after TX */
-               temp.func = &atmegadci_data_tx_sync;
+               /* always setup a valid "pc" pointer for status and sync */
+               temp.pc = xfer->frbuffers + 0;
                temp.len = 0;
                temp.short_pkt = 0;
+               temp.setup_alt_next = 0;
 
-               atmegadci_setup_standard_chain_sub(&temp);
-       }
-       /* check if we should append a status stage */
-       if (xfer->flags_int.control_xfr &&
-           !xfer->flags_int.control_act) {
-
-               /*
-                * Send a DATA1 message and invert the current
-                * endpoint direction.
-                */
-               if (xfer->endpoint & UE_DIR_IN) {
-                       temp.func = &atmegadci_data_rx;
-                       need_sync = 0;
-               } else {
-                       temp.func = &atmegadci_data_tx;
-                       need_sync = 1;
-               }
-               temp.len = 0;
-               temp.short_pkt = 0;
-
-               atmegadci_setup_standard_chain_sub(&temp);
+               /* check if we need to sync */
                if (need_sync) {
                        /* we need a SYNC point after TX */
                        temp.func = &atmegadci_data_tx_sync;
-                       temp.len = 0;
-                       temp.short_pkt = 0;
+                       atmegadci_setup_standard_chain_sub(&temp);
+               }
+
+               /* check if we should append a status stage */
+               if (!xfer->flags_int.control_act) {
+
+                       /*
+                        * Send a DATA1 message and invert the current
+                        * endpoint direction.
+                        */
+                       if (xfer->endpoint & UE_DIR_IN) {
+                               temp.func = &atmegadci_data_rx;
+                               need_sync = 0;
+                       } else {
+                               temp.func = &atmegadci_data_tx;
+                               need_sync = 1;
+                       }
 
                        atmegadci_setup_standard_chain_sub(&temp);
+                       if (need_sync) {
+                               /* we need a SYNC point after TX */
+                               temp.func = &atmegadci_data_tx_sync;
+                               atmegadci_setup_standard_chain_sub(&temp);
+                       }
                }
        }
        /* must have at least one frame! */

Modified: head/sys/dev/usb/controller/atmegadci_atmelarm.c
==============================================================================
--- head/sys/dev/usb/controller/atmegadci_atmelarm.c    Fri Mar 20 21:51:27 
2009        (r190182)
+++ head/sys/dev/usb/controller/atmegadci_atmelarm.c    Fri Mar 20 21:57:54 
2009        (r190183)
@@ -113,7 +113,7 @@ atmegadci_attach(device_t dev)
        device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus);
 
        err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | 
INTR_MPSAFE,
-           NULL, (void *)atmegadci_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
+           NULL, (driver_intr_t *)atmegadci_interrupt, sc, 
&sc->sc_otg.sc_intr_hdl);
        if (err) {
                sc->sc_otg.sc_intr_hdl = NULL;
                goto error;

Modified: head/sys/dev/usb/controller/ehci.c
==============================================================================
--- head/sys/dev/usb/controller/ehci.c  Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/ehci.c  Fri Mar 20 21:57:54 2009        
(r190183)
@@ -117,7 +117,7 @@ struct ehci_std_temp {
        uint8_t shortpkt;
        uint8_t auto_data_toggle;
        uint8_t setup_alt_next;
-       uint8_t short_frames_ok;
+       uint8_t last_frame;
 };
 
 void
@@ -1546,10 +1546,12 @@ ehci_setup_standard_chain_sub(struct ehc
        uint32_t buf_offset;
        uint32_t average;
        uint32_t len_old;
+       uint32_t terminate;
        uint8_t shortpkt_old;
        uint8_t precompute;
 
-       qtd_altnext = htohc32(temp->sc, EHCI_LINK_TERMINATE);
+       terminate = htohc32(temp->sc, EHCI_LINK_TERMINATE);
+       qtd_altnext = terminate;
        td_alt_next = NULL;
        buf_offset = 0;
        shortpkt_old = temp->shortpkt;
@@ -1696,14 +1698,17 @@ restart:
                precompute = 0;
 
                /* setup alt next pointer, if any */
-               if (temp->short_frames_ok) {
-                       if (temp->setup_alt_next) {
-                               td_alt_next = td_next;
-                               qtd_altnext = td_next->qtd_self;
-                       }
+               if (temp->last_frame) {
+                       td_alt_next = NULL;
+                       qtd_altnext = terminate;
                } else {
                        /* we use this field internally */
                        td_alt_next = td_next;
+                       if (temp->setup_alt_next) {
+                               qtd_altnext = td_next->qtd_self;
+                       } else {
+                               qtd_altnext = terminate;
+                       }
                }
 
                /* restore */
@@ -1746,8 +1751,8 @@ ehci_setup_standard_chain(struct usb2_xf
        temp.td = NULL;
        temp.td_next = td;
        temp.qtd_status = 0;
+       temp.last_frame = 0;
        temp.setup_alt_next = xfer->flags_int.short_frames_ok;
-       temp.short_frames_ok = xfer->flags_int.short_frames_ok;
 
        if (xfer->flags_int.control_xfr) {
                if (xfer->pipe->toggle_next) {
@@ -1780,7 +1785,14 @@ ehci_setup_standard_chain(struct usb2_xf
                        temp.len = xfer->frlengths[0];
                        temp.pc = xfer->frbuffers + 0;
                        temp.shortpkt = temp.len ? 1 : 0;
-
+                       /* check for last frame */
+                       if (xfer->nframes == 1) {
+                               /* no STATUS stage yet, SETUP is last */
+                               if (xfer->flags_int.control_act) {
+                                       temp.last_frame = 1;
+                                       temp.setup_alt_next = 0;
+                               }
+                       }
                        ehci_setup_standard_chain_sub(&temp);
                }
                x = 1;
@@ -1798,7 +1810,16 @@ ehci_setup_standard_chain(struct usb2_xf
                x++;
 
                if (x == xfer->nframes) {
-                       temp.setup_alt_next = 0;
+                       if (xfer->flags_int.control_xfr) {
+                               /* no STATUS stage yet, DATA is last */
+                               if (xfer->flags_int.control_act) {
+                                       temp.last_frame = 1;
+                                       temp.setup_alt_next = 0;
+                               }
+                       } else {
+                               temp.last_frame = 1;
+                               temp.setup_alt_next = 0;
+                       }
                }
                /* keep previous data toggle and error count */
 
@@ -1855,6 +1876,8 @@ ehci_setup_standard_chain(struct usb2_xf
                temp.len = 0;
                temp.pc = NULL;
                temp.shortpkt = 0;
+               temp.last_frame = 1;
+               temp.setup_alt_next = 0;
 
                ehci_setup_standard_chain_sub(&temp);
        }

Modified: head/sys/dev/usb/controller/ehci_ixp4xx.c
==============================================================================
--- head/sys/dev/usb/controller/ehci_ixp4xx.c   Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/ehci_ixp4xx.c   Fri Mar 20 21:57:54 2009        
(r190183)
@@ -189,7 +189,7 @@ ehci_ixp_attach(device_t self)
 
 
        err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-           NULL, (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl);
+           NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
        if (err) {
                device_printf(self, "Could not setup irq, %d\n", err);
                sc->sc_intr_hdl = NULL;

Modified: head/sys/dev/usb/controller/ehci_mbus.c
==============================================================================
--- head/sys/dev/usb/controller/ehci_mbus.c     Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/ehci_mbus.c     Fri Mar 20 21:57:54 2009        
(r190183)
@@ -210,7 +210,7 @@ ehci_mbus_attach(device_t self)
            MV_USB_DEVICE_UNDERFLOW);
 
        err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-           NULL, (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl);
+           NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
        if (err) {
                device_printf(self, "Could not setup irq, %d\n", err);
                sc->sc_intr_hdl = NULL;

Modified: head/sys/dev/usb/controller/ehci_pci.c
==============================================================================
--- head/sys/dev/usb/controller/ehci_pci.c      Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/ehci_pci.c      Fri Mar 20 21:57:54 2009        
(r190183)
@@ -338,10 +338,10 @@ ehci_pci_attach(device_t self)
 
 #if (__FreeBSD_version >= 700031)
        err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-           NULL, (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl);
+           NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
 #else
        err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-           (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl);
+           (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
 #endif
        if (err) {
                device_printf(self, "Could not setup irq, %d\n", err);

Modified: head/sys/dev/usb/controller/musb_otg.c
==============================================================================
--- head/sys/dev/usb/controller/musb_otg.c      Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/musb_otg.c      Fri Mar 20 21:57:54 2009        
(r190183)
@@ -1132,8 +1132,8 @@ musbotg_setup_standard_chain(struct usb2
 
        temp.td = NULL;
        temp.td_next = xfer->td_start[0];
-       temp.setup_alt_next = xfer->flags_int.short_frames_ok;
        temp.offset = 0;
+       temp.setup_alt_next = xfer->flags_int.short_frames_ok;
 
        sc = MUSBOTG_BUS2SC(xfer->xroot->bus);
        ep_no = (xfer->endpoint & UE_ADDR);
@@ -1180,7 +1180,13 @@ musbotg_setup_standard_chain(struct usb2
                x++;
 
                if (x == xfer->nframes) {
-                       temp.setup_alt_next = 0;
+                       if (xfer->flags_int.control_xfr) {
+                               if (xfer->flags_int.control_act) {
+                                       temp.setup_alt_next = 0;
+                               }
+                       } else {
+                               temp.setup_alt_next = 0;
+                       }
                }
                if (temp.len == 0) {
 
@@ -1205,23 +1211,24 @@ musbotg_setup_standard_chain(struct usb2
                }
        }
 
-       /* always setup a valid "pc" pointer for status and sync */
-       temp.pc = xfer->frbuffers + 0;
-
-       /* check if we should append a status stage */
-
-       if (xfer->flags_int.control_xfr &&
-           !xfer->flags_int.control_act) {
+       /* check for control transfer */
+       if (xfer->flags_int.control_xfr) {
 
-               /*
-                * Send a DATA1 message and invert the current
-                * endpoint direction.
-                */
-               temp.func = &musbotg_setup_status;
+               /* always setup a valid "pc" pointer for status and sync */
+               temp.pc = xfer->frbuffers + 0;
                temp.len = 0;
                temp.short_pkt = 0;
+               temp.setup_alt_next = 0;
 
-               musbotg_setup_standard_chain_sub(&temp);
+               /* check if we should append a status stage */
+               if (!xfer->flags_int.control_act) {
+                       /*
+                        * Send a DATA1 message and invert the current
+                        * endpoint direction.
+                        */
+                       temp.func = &musbotg_setup_status;
+                       musbotg_setup_standard_chain_sub(&temp);
+               }
        }
        /* must have at least one frame! */
        td = temp.td;

Modified: head/sys/dev/usb/controller/musb_otg_atmelarm.c
==============================================================================
--- head/sys/dev/usb/controller/musb_otg_atmelarm.c     Fri Mar 20 21:51:27 
2009        (r190182)
+++ head/sys/dev/usb/controller/musb_otg_atmelarm.c     Fri Mar 20 21:57:54 
2009        (r190183)
@@ -130,10 +130,10 @@ musbotg_attach(device_t dev)
 
 #if (__FreeBSD_version >= 700031)
        err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | 
INTR_MPSAFE,
-           NULL, (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
+           NULL, (driver_intr_t *)musbotg_interrupt, sc, 
&sc->sc_otg.sc_intr_hdl);
 #else
        err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | 
INTR_MPSAFE,
-           (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
+           (driver_intr_t *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
 #endif
        if (err) {
                sc->sc_otg.sc_intr_hdl = NULL;

Modified: head/sys/dev/usb/controller/ohci.c
==============================================================================
--- head/sys/dev/usb/controller/ohci.c  Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/ohci.c  Fri Mar 20 21:57:54 2009        
(r190183)
@@ -115,7 +115,7 @@ struct ohci_std_temp {
        uint16_t max_frame_size;
        uint8_t shortpkt;
        uint8_t setup_alt_next;
-       uint8_t short_frames_ok;
+       uint8_t last_frame;
 };
 
 static struct ohci_hcca *
@@ -1020,6 +1020,23 @@ ohci_check_transfer_sub(struct usb2_xfer
                usb2_pc_cpu_flush(ed->page_cache);
 
                DPRINTFN(13, "xfer=%p following alt next\n", xfer);
+
+               /*
+                * Make sure that the OHCI re-scans the schedule by
+                * writing the BLF and CLF bits:
+                */
+
+               if (xfer->xroot->udev->pwr_save.suspended) {
+                       /* nothing to do */
+               } else if (xfer->pipe->methods == &ohci_device_bulk_methods) {
+                       ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
+
+                       OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
+               } else if (xfer->pipe->methods == &ohci_device_ctrl_methods) {
+                       ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
+
+                       OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
+               }
        }
 }
 
@@ -1034,7 +1051,6 @@ static uint8_t
 ohci_check_transfer(struct usb2_xfer *xfer)
 {
        ohci_ed_t *ed;
-       uint32_t ed_flags;
        uint32_t ed_headp;
        uint32_t ed_tailp;
 
@@ -1043,12 +1059,10 @@ ohci_check_transfer(struct usb2_xfer *xf
        ed = xfer->qh_start[xfer->flags_int.curr_dma_set];
 
        usb2_pc_cpu_invalidate(ed->page_cache);
-       ed_flags = le32toh(ed->ed_flags);
        ed_headp = le32toh(ed->ed_headp);
        ed_tailp = le32toh(ed->ed_tailp);
 
-       if ((ed_flags & OHCI_ED_SKIP) ||
-           (ed_headp & OHCI_HALTED) ||
+       if ((ed_headp & OHCI_HALTED) ||
            (((ed_headp ^ ed_tailp) & (~0xF)) == 0)) {
                if (xfer->pipe->methods == &ohci_device_isoc_methods) {
                        /* isochronous transfer */
@@ -1379,10 +1393,9 @@ restart:
                precompute = 0;
 
                /* setup alt next pointer, if any */
-               if (temp->short_frames_ok) {
-                       if (temp->setup_alt_next) {
-                               td_alt_next = td_next;
-                       }
+               if (temp->last_frame) {
+                       /* no alternate next */
+                       td_alt_next = NULL;
                } else {
                        /* we use this field internally */
                        td_alt_next = td_next;
@@ -1425,8 +1438,8 @@ ohci_setup_standard_chain(struct usb2_xf
 
        temp.td = NULL;
        temp.td_next = td;
+       temp.last_frame = 0;
        temp.setup_alt_next = xfer->flags_int.short_frames_ok;
-       temp.short_frames_ok = xfer->flags_int.short_frames_ok;
 
        methods = xfer->pipe->methods;
 
@@ -1441,7 +1454,14 @@ ohci_setup_standard_chain(struct usb2_xf
                        temp.len = xfer->frlengths[0];
                        temp.pc = xfer->frbuffers + 0;
                        temp.shortpkt = temp.len ? 1 : 0;
-
+                       /* check for last frame */
+                       if (xfer->nframes == 1) {
+                               /* no STATUS stage yet, SETUP is last */
+                               if (xfer->flags_int.control_act) {
+                                       temp.last_frame = 1;
+                                       temp.setup_alt_next = 0;
+                               }
+                       }
                        ohci_setup_standard_chain_sub(&temp);
 
                        /*
@@ -1482,7 +1502,16 @@ ohci_setup_standard_chain(struct usb2_xf
                x++;
 
                if (x == xfer->nframes) {
-                       temp.setup_alt_next = 0;
+                       if (xfer->flags_int.control_xfr) {
+                               /* no STATUS stage yet, DATA is last */
+                               if (xfer->flags_int.control_act) {
+                                       temp.last_frame = 1;
+                                       temp.setup_alt_next = 0;
+                               }
+                       } else {
+                               temp.last_frame = 1;
+                               temp.setup_alt_next = 0;
+                       }
                }
                if (temp.len == 0) {
 
@@ -1523,11 +1552,14 @@ ohci_setup_standard_chain(struct usb2_xf
                temp.len = 0;
                temp.pc = NULL;
                temp.shortpkt = 0;
+               temp.last_frame = 1;
+               temp.setup_alt_next = 0;
 
                ohci_setup_standard_chain_sub(&temp);
        }
        td = temp.td;
 
+       /* Ensure that last TD is terminating: */
        td->td_next = htole32(OHCI_TD_NEXT_END);
        td->td_flags &= ~htole32(OHCI_TD_INTR_MASK);
        td->td_flags |= htole32(OHCI_TD_SET_DI(1));

Modified: head/sys/dev/usb/controller/ohci_atmelarm.c
==============================================================================
--- head/sys/dev/usb/controller/ohci_atmelarm.c Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/ohci_atmelarm.c Fri Mar 20 21:57:54 2009        
(r190183)
@@ -111,10 +111,10 @@ ohci_atmelarm_attach(device_t dev)
 
 #if (__FreeBSD_version >= 700031)
        err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | 
INTR_MPSAFE,
-           NULL, (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl);
+           NULL, (driver_intr_t *)ohci_interrupt, sc, 
&sc->sc_ohci.sc_intr_hdl);
 #else
        err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | 
INTR_MPSAFE,
-           (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl);
+           (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl);
 #endif
        if (err) {
                sc->sc_ohci.sc_intr_hdl = NULL;

Modified: head/sys/dev/usb/controller/ohci_pci.c
==============================================================================
--- head/sys/dev/usb/controller/ohci_pci.c      Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/ohci_pci.c      Fri Mar 20 21:57:54 2009        
(r190183)
@@ -289,10 +289,10 @@ ohci_pci_attach(device_t self)
 
 #if (__FreeBSD_version >= 700031)
        err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-           NULL, (void *)(void *)ohci_interrupt, sc, &sc->sc_intr_hdl);
+           NULL, (driver_intr_t *)ohci_interrupt, sc, &sc->sc_intr_hdl);
 #else
        err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-           (void *)(void *)ohci_interrupt, sc, &sc->sc_intr_hdl);
+           (driver_intr_t *)ohci_interrupt, sc, &sc->sc_intr_hdl);
 #endif
        if (err) {
                device_printf(self, "Could not setup irq, %d\n", err);

Modified: head/sys/dev/usb/controller/uhci.c
==============================================================================
--- head/sys/dev/usb/controller/uhci.c  Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/uhci.c  Fri Mar 20 21:57:54 2009        
(r190183)
@@ -124,7 +124,7 @@ struct uhci_std_temp {
        uint16_t max_frame_size;
        uint8_t shortpkt;
        uint8_t setup_alt_next;
-       uint8_t short_frames_ok;
+       uint8_t last_frame;
 };
 
 extern struct usb2_bus_methods uhci_bus_methods;
@@ -1253,30 +1253,33 @@ uhci_check_transfer_sub(struct usb2_xfer
        td_self = td->td_self;
        td_alt_next = td->alt_next;
 
-       if ((td->td_token ^ td_token) & htole32(UHCI_TD_SET_DT(1))) {
+       if (xfer->flags_int.control_xfr)
+               goto skip;      /* don't touch the DT value! */
 
-               /*
-                * The data toggle is wrong and
-                * we need to switch it !
-                */
+       if (!((td->td_token ^ td_token) & htole32(UHCI_TD_SET_DT(1))))
+               goto skip;      /* data toggle has correct value */
 
-               while (1) {
+       /*
+        * The data toggle is wrong and we need to toggle it !
+        */
+       while (1) {
 
-                       td->td_token ^= htole32(UHCI_TD_SET_DT(1));
-                       usb2_pc_cpu_flush(td->page_cache);
+               td->td_token ^= htole32(UHCI_TD_SET_DT(1));
+               usb2_pc_cpu_flush(td->page_cache);
 
-                       if (td == xfer->td_transfer_last) {
-                               /* last transfer */
-                               break;
-                       }
-                       td = td->obj_next;
+               if (td == xfer->td_transfer_last) {
+                       /* last transfer */
+                       break;
+               }
+               td = td->obj_next;
 
-                       if (td->alt_next != td_alt_next) {
-                               /* next frame */
-                               break;
-                       }
+               if (td->alt_next != td_alt_next) {
+                       /* next frame */
+                       break;
                }
        }
+skip:
+
        /* update the QH */
        qh->qh_e_next = td_self;
        usb2_pc_cpu_flush(qh->page_cache);
@@ -1631,10 +1634,8 @@ restart:
                precompute = 0;
 
                /* setup alt next pointer, if any */
-               if (temp->short_frames_ok) {
-                       if (temp->setup_alt_next) {
-                               td_alt_next = td_next;
-                       }
+               if (temp->last_frame) {
+                       td_alt_next = NULL;
                } else {
                        /* we use this field internally */
                        td_alt_next = td_next;
@@ -1673,8 +1674,8 @@ uhci_setup_standard_chain(struct usb2_xf
 
        temp.td = NULL;
        temp.td_next = td;
+       temp.last_frame = 0;
        temp.setup_alt_next = xfer->flags_int.short_frames_ok;
-       temp.short_frames_ok = xfer->flags_int.short_frames_ok;
 
        uhci_mem_layout_init(&temp.ml, xfer);
 
@@ -1707,7 +1708,14 @@ uhci_setup_standard_chain(struct usb2_xf
                        temp.len = xfer->frlengths[0];
                        temp.ml.buf_pc = xfer->frbuffers + 0;
                        temp.shortpkt = temp.len ? 1 : 0;
-
+                       /* check for last frame */
+                       if (xfer->nframes == 1) {
+                               /* no STATUS stage yet, SETUP is last */
+                               if (xfer->flags_int.control_act) {
+                                       temp.last_frame = 1;
+                                       temp.setup_alt_next = 0;
+                               }
+                       }
                        uhci_setup_standard_chain_sub(&temp);
                }
                x = 1;
@@ -1725,7 +1733,16 @@ uhci_setup_standard_chain(struct usb2_xf
                x++;
 
                if (x == xfer->nframes) {
-                       temp.setup_alt_next = 0;
+                       if (xfer->flags_int.control_xfr) {
+                               /* no STATUS stage yet, DATA is last */
+                               if (xfer->flags_int.control_act) {
+                                       temp.last_frame = 1;
+                                       temp.setup_alt_next = 0;
+                               }
+                       } else {
+                               temp.last_frame = 1;
+                               temp.setup_alt_next = 0;
+                       }
                }
                /*
                 * Keep previous data toggle,
@@ -1780,11 +1797,14 @@ uhci_setup_standard_chain(struct usb2_xf
                temp.len = 0;
                temp.ml.buf_pc = NULL;
                temp.shortpkt = 0;
+               temp.last_frame = 1;
+               temp.setup_alt_next = 0;
 
                uhci_setup_standard_chain_sub(&temp);
        }
        td = temp.td;
 
+       /* Ensure that last TD is terminating: */
        td->td_next = htole32(UHCI_PTR_T);
 
        /* set interrupt bit */

Modified: head/sys/dev/usb/controller/uhci_pci.c
==============================================================================
--- head/sys/dev/usb/controller/uhci_pci.c      Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/uhci_pci.c      Fri Mar 20 21:57:54 2009        
(r190183)
@@ -323,10 +323,10 @@ uhci_pci_attach(device_t self)
 
 #if (__FreeBSD_version >= 700031)
        err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-           NULL, (void *)(void *)uhci_interrupt, sc, &sc->sc_intr_hdl);
+           NULL, (driver_intr_t *)uhci_interrupt, sc, &sc->sc_intr_hdl);
 #else
        err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-           (void *)(void *)uhci_interrupt, sc, &sc->sc_intr_hdl);
+           (driver_intr_t *)uhci_interrupt, sc, &sc->sc_intr_hdl);
 #endif
 
        if (err) {

Modified: head/sys/dev/usb/controller/uss820dci.c
==============================================================================
--- head/sys/dev/usb/controller/uss820dci.c     Fri Mar 20 21:51:27 2009        
(r190182)
+++ head/sys/dev/usb/controller/uss820dci.c     Fri Mar 20 21:57:54 2009        
(r190183)
@@ -836,8 +836,8 @@ uss820dci_setup_standard_chain(struct us
 
        temp.td = NULL;
        temp.td_next = xfer->td_start[0];
-       temp.setup_alt_next = xfer->flags_int.short_frames_ok;
        temp.offset = 0;
+       temp.setup_alt_next = xfer->flags_int.short_frames_ok;
 
        sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
        ep_no = (xfer->endpoint & UE_ADDR);
@@ -851,6 +851,12 @@ uss820dci_setup_standard_chain(struct us
                        temp.len = xfer->frlengths[0];
                        temp.pc = xfer->frbuffers + 0;
                        temp.short_pkt = temp.len ? 1 : 0;
+                       /* check for last frame */
+                       if (xfer->nframes == 1) {
+                               /* no STATUS stage yet, SETUP is last */
+                               if (xfer->flags_int.control_act)
+                                       temp.setup_alt_next = 0;
+                       }
 
                        uss820dci_setup_standard_chain_sub(&temp);
                }
@@ -878,7 +884,13 @@ uss820dci_setup_standard_chain(struct us
                x++;
 
                if (x == xfer->nframes) {
-                       temp.setup_alt_next = 0;
+                       if (xfer->flags_int.control_xfr) {
+                               if (xfer->flags_int.control_act) {
+                                       temp.setup_alt_next = 0;
+                               }
+                       } else {
+                               temp.setup_alt_next = 0;
+                       }
                }
                if (temp.len == 0) {
 
@@ -903,37 +915,39 @@ uss820dci_setup_standard_chain(struct us
                }
        }
 
-       /* always setup a valid "pc" pointer for status and sync */
-       temp.pc = xfer->frbuffers + 0;
-
-       /* check if we should append a status stage */
-
-       if (xfer->flags_int.control_xfr &&
-           !xfer->flags_int.control_act) {
+       /* check for control transfer */
+       if (xfer->flags_int.control_xfr) {
                uint8_t need_sync;
 
-               /*
-                * Send a DATA1 message and invert the current
-                * endpoint direction.
-                */
-               if (xfer->endpoint & UE_DIR_IN) {
-                       temp.func = &uss820dci_data_rx;
-                       need_sync = 0;
-               } else {
-                       temp.func = &uss820dci_data_tx;
-                       need_sync = 1;
-               }
+               /* always setup a valid "pc" pointer for status and sync */
+               temp.pc = xfer->frbuffers + 0;
                temp.len = 0;
                temp.short_pkt = 0;
+               temp.setup_alt_next = 0;
 
-               uss820dci_setup_standard_chain_sub(&temp);
-               if (need_sync) {
-                       /* we need a SYNC point after TX */
-                       temp.func = &uss820dci_data_tx_sync;
+               /* check if we should append a status stage */
+               if (!xfer->flags_int.control_act) {
+
+                       /*
+                        * Send a DATA1 message and invert the current
+                        * endpoint direction.
+                        */
+                       if (xfer->endpoint & UE_DIR_IN) {
+                               temp.func = &uss820dci_data_rx;
+                               need_sync = 0;
+                       } else {
+                               temp.func = &uss820dci_data_tx;
+                               need_sync = 1;
+                       }
                        temp.len = 0;
                        temp.short_pkt = 0;
 
                        uss820dci_setup_standard_chain_sub(&temp);
+                       if (need_sync) {
+                               /* we need a SYNC point after TX */
+                               temp.func = &uss820dci_data_tx_sync;
+                               uss820dci_setup_standard_chain_sub(&temp);
+                       }
                }
        }
        /* must have at least one frame! */

Modified: head/sys/dev/usb/controller/uss820dci_atmelarm.c
==============================================================================
--- head/sys/dev/usb/controller/uss820dci_atmelarm.c    Fri Mar 20 21:51:27 
2009        (r190182)
+++ head/sys/dev/usb/controller/uss820dci_atmelarm.c    Fri Mar 20 21:57:54 
2009        (r190183)
@@ -170,10 +170,10 @@ uss820_atmelarm_attach(device_t dev)
 
 #if (__FreeBSD_version >= 700031)
        err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-           NULL, (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
+           NULL, (driver_intr_t *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
 #else
        err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-           (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
+           (driver_intr_t *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
 #endif
        if (err) {
                sc->sc_intr_hdl = NULL;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to