On Mon, 15 Mar 2010, Oliver Neukum wrote: > > Here's a patch. Oliver, does it fix your problem? > > It works. Below is an updated version, based on a comment from James Bottomley. Can you test it using both the text and binary usbmon interfaces? Pete has a program for the binary interface on his web page: http://people.redhat.com/zaitcev/linux/usbmon-5.4.tar.gz Alan Stern Index: usb-2.6/drivers/usb/mon/usb_mon.h =================================================================== --- usb-2.6.orig/drivers/usb/mon/usb_mon.h +++ usb-2.6/drivers/usb/mon/usb_mon.h @@ -72,4 +72,6 @@ extern const struct file_operations mon_ extern struct mon_bus mon_bus0; /* Only for redundant checks */ +extern void usb_sg_sync_for_cpu(struct urb *urb, int nelems); + #endif /* __USB_MON_H */ Index: usb-2.6/drivers/usb/mon/mon_bin.c =================================================================== --- usb-2.6.orig/drivers/usb/mon/mon_bin.c +++ usb-2.6/drivers/usb/mon/mon_bin.c @@ -410,6 +410,7 @@ static unsigned int mon_bin_get_data(con *flag = 'Z'; return length; } + usb_sg_sync_for_cpu(urb, 1); mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); length = 0; @@ -421,6 +422,7 @@ static unsigned int mon_bin_get_data(con } /* Copy up to the first non-addressable segment */ + usb_sg_sync_for_cpu(urb, urb->num_sgs); for_each_sg(urb->sg->sg, sg, urb->num_sgs, i) { if (length == 0 || PageHighMem(sg_page(sg))) break; Index: usb-2.6/drivers/usb/mon/mon_text.c =================================================================== --- usb-2.6.orig/drivers/usb/mon/mon_text.c +++ usb-2.6/drivers/usb/mon/mon_text.c @@ -170,6 +170,7 @@ static inline char mon_text_get_data(str src = sg_virt(sg); } + usb_sg_sync_for_cpu(urb, 1); memcpy(ep->data, src, len); return 0; } Index: usb-2.6/drivers/usb/core/message.c =================================================================== --- usb-2.6.orig/drivers/usb/core/message.c +++ usb-2.6/drivers/usb/core/message.c @@ -467,6 +467,7 @@ int usb_sg_init(struct usb_sg_request *i io->urbs[i]->transfer_buffer = NULL; if (dma) { + io->urbs[i]->sg = (struct usb_sg_request *) sg; io->urbs[i]->transfer_dma = sg_dma_address(sg); len = sg_dma_len(sg); } else { @@ -643,6 +644,43 @@ void usb_sg_cancel(struct usb_sg_request } EXPORT_SYMBOL_GPL(usb_sg_cancel); +/** + * usb_sg_sync_for_cpu -- give ownership of DMA buffers to the CPU + * @urb: URB whose buffers should be affected + * @nelems: number of sg elements to affect + * + * This allows the CPU to access @urb's sg transfer buffers after @urb + * has completed but before sg_clean() has unmapped the buffers for DMA. + * This is intended solely for use by usbmon. + */ +void usb_sg_sync_for_cpu(struct urb *urb, int nelems) +{ + struct scatterlist *sg; + struct device *dev; + enum dma_data_direction dir; + + if (!(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + return; /* Either not sg or not DMA */ + + if (urb->num_sgs == 0) { /* HCD has no native sg support */ + sg = (struct scatterlist *) urb->sg; + if (!sg) + return; /* Coherent mapping, not sg-mapped */ + nelems = 1; + } else { /* HCD has native sg support */ + sg = urb->sg->sg; + } + + dev = urb->dev->bus->controller; + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + if (nelems > 1) + dma_sync_sg_for_cpu(dev, sg, nelems, dir); + else + dma_sync_single_for_cpu(dev, sg_dma_address(sg), + sg_dma_len(sg), dir); +} +EXPORT_SYMBOL_GPL(usb_sg_sync_for_cpu); + /*-------------------------------------------------------------------*/ /** -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html