David Brownell wrote: > > > And I have also found a bug but it seems it's not the 'right' one > > for this problem: > > > > urb_free_priv () just unmaps the last part (belonging to the last TD) > > of the data buffer. > > I'll have to patch that. Clearly I was thinking I made OHCI do > this the same way as EHCI ... not quite! :) > > This won't be an issue on x86 or other platforms that implement > the mappings by virt_to_bus() calls, or for transfers that fit into > exactly one TD. Since 4 KBytes fits into one OHCI TD, that > explains why this one may not have been seen "in the wild" yet. > Hi Dave, here is the patch I have used so far. -Roman > - Dave > > _______________________________________________ > [EMAIL PROTECTED] > To unsubscribe, use the last form field at: > http://lists.sourceforge.net/lists/listinfo/linux-usb-devel
--- drivers/usb.org/usb-ohci.c Sun Jun 3 13:49:15 2001 +++ drivers/usb/usb-ohci.c Thu Jun 7 17:19:21 2001 @@ -136,28 +136,39 @@ { int i; int last = urb_priv->length - 1; + int len; + int dir; struct td *td; - for (i = 0; i <= last; i++) { - td = urb_priv->td [i]; - if (td) { - int len; - int dir; + if (last >= 0) { - if ((td->hwINFO & cpu_to_le32 (TD_DP)) == TD_DP_SETUP) { - len = 8; - dir = PCI_DMA_TODEVICE; - } else if (i == last) { - len = td->urb->transfer_buffer_length, - dir = usb_pipeout (td->urb->pipe) + /* ISOC, BULK, INTR data buffer starts at td 0 + * CTRL setup starts at td 0 */ + td = urb_priv->td [0]; + + len = td->urb->transfer_buffer_length, + dir = usb_pipeout (td->urb->pipe) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE; - } else - len = dir = 0; - if (len && td->data_dma) - pci_unmap_single (hc->ohci_dev, - td->data_dma, len, dir); - td_free (hc, urb_priv->td [i]); + + /* unmap CTRL URB setup */ + if (usb_pipecontrol (td->urb->pipe)) { + pci_unmap_single (hc->ohci_dev, + td->data_dma, 8, PCI_DMA_TODEVICE); + + /* CTRL data buffer starts at td 1 if len > 0 */ + if (len && last > 0) + td = urb_priv->td [1]; + } + + /* unmap data buffer */ + if (len && td->data_dma) + pci_unmap_single (hc->ohci_dev, td->data_dma, len, dir); + + for (i = 0; i <= last; i++) { + td = urb_priv->td [i]; + if (td) + td_free (hc, td); } }