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);
}
}