USB: add binary API to usbmon

This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.

The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.

This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.

Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>


diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c
index ddcfc01..140cc80 100644
--- a/drivers/usb/mon/mon_dma.c
+++ b/drivers/usb/mon/mon_dma.c
@@ -48,6 +48,36 @@
 	local_irq_restore(flags);
 	return 0;
 }
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+	unsigned long flags;
+	unsigned int step_len;
+	struct page *pg;
+	unsigned char *map;
+	unsigned long page_off, page_len;
+
+	local_irq_save(flags);
+	while (length) {
+		/* compute number of bytes we are going to copy in this page */
+		step_len = length;
+		page_off = dma_addr & (PAGE_SIZE-1);
+		page_len = PAGE_SIZE - page_off;
+		if (page_len < step_len)
+			step_len = page_len;
+
+		/* copy data and advance pointers */
+		pg = phys_to_page(dma_addr);
+		map = kmap_atomic(pg, KM_IRQ0);
+		offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
+		kunmap_atomic(map, KM_IRQ0);
+		dma_addr += step_len;
+		length -= step_len;
+	}
+	local_irq_restore(flags);
+}
+
 #endif /* __i386__ */
 
 #ifndef MON_HAS_UNMAP
@@ -55,4 +85,11 @@
 {
 	return 'D';
 }
-#endif
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+	;
+}
+
+#endif /* MON_HAS_UNMAP */