diff -urp usbutils-0.72/configure.in usbutils-0.72-p3/configure.in
--- usbutils-0.72/configure.in	2006-02-18 16:14:41.000000000 -0800
+++ usbutils-0.72-p3/configure.in	2006-11-25 14:37:21.000000000 -0800
@@ -20,7 +20,7 @@ AC_PROG_LN_S
 AC_FUNC_ALLOCA
 AC_HEADER_DIRENT
 AC_HEADER_STDC
-AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/ioctl.h sys/param.h unistd.h getopt.h errno.h ])
+AC_CHECK_HEADERS([ctype.h fcntl.h inttypes.h stdlib.h string.h sys/ioctl.h sys/param.h unistd.h getopt.h errno.h ])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -28,11 +28,12 @@ AC_TYPE_OFF_T
 AC_TYPE_SIZE_T
 
 # Checks for library functions.
+# AC_CHECK_LIB makes usbmon to link to libusb, which is unnecesary, but...
 AC_FUNC_MALLOC
 AC_FUNC_VPRINTF
 AC_CHECK_FUNCS([getcwd memset getopt_long strchr strerror strstr strtoul uname])
 AC_CHECK_LIB(usb, usb_get_string_simple, ,
-	[AC_MSG_ERROR(get libusb 0.1.8 or newer)])
+	[AC_MSG_ERROR(get libusb{-devel} 0.1.8 or newer)])
 
 #AC_ARG_ENABLE(usbmodules,
 #	[  --enable-usbmodules     build usbmodules (for Linux 2.4)],
diff -urp usbutils-0.72/Makefile.am usbutils-0.72-p3/Makefile.am
--- usbutils-0.72/Makefile.am	2006-02-18 15:48:13.000000000 -0800
+++ usbutils-0.72-p3/Makefile.am	2006-11-25 14:12:15.000000000 -0800
@@ -4,16 +4,18 @@ AM_CPPFLAGS = -DUSBIDS_FILE='"@datadir@/
 
 AM_CFLAGS = -Wall -W -Wunused
 
-sbin_PROGRAMS = lsusb
+sbin_PROGRAMS = lsusb usbmon
 
 lsusb_SOURCES = lsusb.c \
 	names.c names.h \
 	devtree.c devtree.h list.h \
 	usbmisc.c usbmisc.h
 
+usbmon_SOURCES = usbmon.c
+
 data_DATA = usb.ids
 
-man_MANS = lsusb.8
+man_MANS = lsusb.8 usbmon.8
 
 # usbmodules is needed only with 2.4 based hotplugging, and is OBSOLETE 
 
diff -urpN usbutils-0.72/usbmon.8 usbutils-0.72-p3/usbmon.8
--- usbutils-0.72/usbmon.8	1969-12-31 16:00:00.000000000 -0800
+++ usbutils-0.72-p3/usbmon.8	2006-11-25 13:56:55.000000000 -0800
@@ -0,0 +1,117 @@
+.TH usbmon 8 "25 January 2005" "usbutils-0.72" "Linux USB Utilities"
+.IX usbmon
+.SH NAME
+usbmon \- monitor USB traffic
+.SH SYNOPSIS
+.B usbmon
+[
+.B -i
+.I usb_bus_num
+]
+.SH DESCRIPTION
+.B usbmon
+allows to capture USB traffic for analysis in the manner similar to
+.BR tcpdump (8)
+
+To make use of this program, you need to have a Linux kernel
+which supports the binary "usbmon" interface
+(e.g., Linux kernel 2.6.20 or newer).
+
+.SH OPTIONS
+.TP
+.B \-i
+Listen on \fIusb_bus_num\fP. If unspecified,
+.I usbmon
+attempts to listen on the pseudo-bus number zero,
+which is supposed to capture all packets on all buses.
+However, this functionality is not implemented by any Linux kernel to date.
+So, in practical terms, user has to specify the bus number always.
+The bus number may be determined by examining the output of lsusb(8).
+
+.SH OUTPUT FORMAT
+.LP
+Default output of
+.I usbmon
+contains one text line per an event. The event corresponds to I/O operations
+on the boundary of Host Controller Driver (HCD).
+This includes events of the following types:
+Submission,
+Callback,
+Error.
+Every line consists
+of whitespace separated words. The number or position of words may depend
+on the event type, but there is a set of words, common for all types.
+.LP
+Here is the list of words, from left to right:
+.PP
+- URB Tag. This is used to identify URBs is normally a kernel mode address
+of the URB structure in hexadecimal.
+.PP
+- Timestamp in microseconds, a decimal number. The timestamp's resolution
+depends on available clock, and so it can be much worse than a microsecond
+(if the implementation uses jiffies, for example).
+.PP
+- Event Type. This type refers to the format of the event, not URB type.
+Available types are: S - submission, C - callback, E - submission error.
+.PP
+- "Pipe". The pipe concept is deprecated. This is a composite word, used to
+be derived from information in pipes. It consists of three fields, separated
+by colons: URB type and direction, Device address, Endpoint number.
+Type and direction are encoded with two bytes in the following manner:
+.PP
+    Ci Co   Control input and output
+    Zi Zo   Isochronous input and output
+    Ii Io   Interrupt input and output
+    Bi Bo   Bulk input and output
+.PP
+Device address and Endpoint number are 3-digit and 2-digit (respectively)
+decimal numbers, with leading zeroes.
+.PP
+- URB Status. In most cases, this field contains a number, sometimes negative,
+which represents a "status" field of the URB. This field makes no sense for
+submissions, but is present anyway to help scripts with parsing. When an
+error occurs, the field contains the error code. In case of a submission of
+a Control packet, this field contains a Setup Tag instead of an error code.
+It is easy to tell whether the Setup Tag is present because it is never a
+number. Thus if scripts find a number in this field, they proceed to read
+Data Length. If they find something else, like a letter, they read the setup
+packet before reading the Data Length.
+.PP
+- Setup packet, if present, consists of 5 words: one of each for bmRequestType,
+bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0.
+These words are safe to decode if Setup Tag was 's'. Otherwise, the setup
+packet was present, but not captured, and the fields contain filler.
+.PP
+- Data Length. For submissions, this is the requested length. For callbacks,
+this is the actual length.
+.PP
+- Data tag. The usbmon may not always capture data, even if length is nonzero.
+The data words are present only if this tag is '='.
+.PP
+- Data words follow, in big endian hexadecimal format. Notice that they are
+not machine words, but really just a byte stream split into words to make
+it easier to read. Thus, the last word may contain from one to four bytes.
+The length of collected data is limited and can be less than the data length
+report in Data Length word.
+
+.SH FILES
+.TP
+.B /proc/devices
+This file is read to determine the major of /dev/usbmonN if such node does
+not exist in the system.
+.TP
+.B /dev/usbmonN
+The
+.I usbmon
+attempts to open
+.I /dev/usbmon{N},
+where N is the bus number.
+If the node does not exist,
+.I usbmon
+creates it.
+
+.SH SEE ALSO
+.BR lsusb (8)
+
+.SH AUTHOR
+Pete Zaitcev, <zaitcev@redhat.com>.
diff -urpN usbutils-0.72/usbmon.c usbutils-0.72-p3/usbmon.c
--- usbutils-0.72/usbmon.c	1969-12-31 16:00:00.000000000 -0800
+++ usbutils-0.72-p3/usbmon.c	2006-11-25 14:10:29.000000000 -0800
@@ -0,0 +1,349 @@
+/*
+ * usbmon: Front-end for usbmon
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+
+#define TAG "usbmon"
+
+#ifdef __GNUC__
+#define __unused __attribute__((unused))
+#else
+#define __unused /**/
+#endif
+
+struct usbmon_packet {
+	uint64_t id;		/* URB ID - from submission to callback */
+	unsigned char type;	/* Same as in text API; extensible. */
+	unsigned char xfer_type;	/* ISO, Intr, Control, Bulk; 0x80 IN */
+	unsigned char epnum;	/* Endpoint number */
+	unsigned char devnum;	/* Device address */
+	unsigned short busnum;	/* Bus number */
+	char flag_setup;
+	char flag_data;
+	int64_t ts_sec;		/* gettimeofday */
+	int32_t ts_usec;	/* gettimeofday */
+	int status;
+	unsigned int length;	/* Length of data (submitted or actual) */
+	unsigned int len_cap;	/* Delivered length */
+	unsigned char setup[8];	/* Only for Control S-type */
+};
+
+#define PIPE_ISOCHRONOUS		0
+#define PIPE_INTERRUPT			1
+#define PIPE_CONTROL			2
+#define PIPE_BULK			3
+
+#define MON_IOC_MAGIC 0x92
+
+#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
+
+#define MON_IOCX_URB  _IOWR(MON_IOC_MAGIC, 2, struct usbmon_packet)
+
+#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct usbmon_stats)
+
+#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
+
+#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
+
+struct usbmon_get_arg {
+	struct usbmon_packet *hdr;	/* Only 48 bytes, not 64. */
+	void *data;
+	size_t alloc;			/* Length of data (can be zero) */
+};
+
+#define MON_IOCX_GET   _IOW(MON_IOC_MAGIC, 6, struct usbmon_get_arg)
+
+/*
+ */
+struct params {
+	int ifnum;	/* USB bus number */
+	char *devname;	/* /dev/usbmonN */
+	int data_size;
+};
+
+void Usage(void);
+
+void print_urb(struct usbmon_packet *ep, unsigned char *data);
+void parse_params(struct params *p, char **argv);
+void make_device(const struct params *p);
+int find_major(void);
+struct params par;
+
+int main(int argc __unused, char **argv)
+{
+	int fd;
+	struct usbmon_packet hdrb;
+	struct usbmon_get_arg getb;
+	unsigned char *data_buff;
+	int rc;
+
+	if (sizeof(struct usbmon_packet) != 48) {
+		extern void usbmon_packet_size_is_bolixed(void);
+		usbmon_packet_size_is_bolixed();	/* link-time error */
+	}
+
+	parse_params(&par, argv+1);
+
+	/*
+	 * Two reasons to do this:
+	 * 1. Reduce weird error messages.
+	 * 2. If we create device nodes, we want them owned by root.
+	 */
+	if (geteuid() != 0) {
+		fprintf(stderr, TAG ": Must run as root\n");
+		exit(1);
+	}
+
+	if ((fd = open(par.devname, O_RDWR)) == -1) {
+		if (errno == ENOENT) {
+			make_device(&par);
+			if ((fd = open(par.devname, O_RDWR)) == -1) {
+				fprintf(stderr, TAG ": Can't open %s: %s\n",
+				    par.devname, strerror(errno));
+				exit(1);
+			}
+		} else {
+			fprintf(stderr, TAG ": Can't open %s: %s\n",
+			    par.devname, strerror(errno));
+			exit(1);
+		}
+	}
+
+	rc = ioctl(fd, MON_IOCQ_RING_SIZE, 0);
+	printf("Ring size: %d\n", rc);
+
+	if ((data_buff = malloc(par.data_size)) == NULL) {
+		fprintf(stderr, TAG ": No core\n");
+		exit(1);
+	}
+
+	for (;;) {
+		getb.hdr = &hdrb;
+		getb.data = data_buff;
+		getb.alloc = par.data_size;
+		if ((rc = ioctl(fd, MON_IOCX_GET, &getb)) != 0) {
+			/* Maybe keep going later, for some errnos. */
+			fprintf(stderr, TAG ": No core\n");
+			exit(1);
+		}
+
+		print_urb(&hdrb, data_buff);
+	}
+
+	// return 0;
+}
+
+void print_urb(struct usbmon_packet *ep, unsigned char *data)
+{
+	char printf_buf[160];
+	int DATA_MAX = 32;	/* XXX Needs new printf_buf if changed */
+	int cnt, limit;
+	char *pbuf;
+	char udir, utype;
+	int data_len, i;
+
+	cnt = 0;
+	pbuf = printf_buf;
+	limit = sizeof(printf_buf);
+
+	udir = ((ep->xfer_type & 0x80) != 0) ? 'i' : 'o';
+	switch (ep->xfer_type & 0x3) {
+	case PIPE_ISOCHRONOUS:	utype = 'Z'; break;
+	case PIPE_INTERRUPT:	utype = 'I'; break;
+	case PIPE_CONTROL:	utype = 'C'; break;
+	default: /* PIPE_BULK */  utype = 'B';
+	}
+	cnt += snprintf(pbuf + cnt, limit - cnt,
+	    "%lx %u %c %c%c:%03u:%02u",
+	    ep->id,
+	    (unsigned int)(ep->ts_sec & 0xFFFF) * 1000000 + ep->ts_usec,
+	    ep->type,
+	    utype, udir, ep->devnum, ep->epnum);
+
+	if (ep->flag_setup == 0) {   /* Setup packet is present and captured */
+		cnt += snprintf(pbuf + cnt, limit - cnt,
+		    " s %02x %02x %04x %04x %04x",
+		    ep->setup[0],
+		    ep->setup[1],
+		    (ep->setup[3] << 8) | ep->setup[2],
+		    (ep->setup[5] << 8) | ep->setup[4],
+		    (ep->setup[7] << 8) | ep->setup[6]);
+	} else if (ep->flag_setup != '-') { /* Unable to capture setup packet */
+		cnt += snprintf(pbuf + cnt, limit - cnt,
+		    " %c __ __ ____ ____ ____", ep->flag_setup);
+	} else {                     /* No setup for this kind of URB */
+		cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->status);
+	}
+	cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->length);
+
+	if (ep->length > 0) {
+		if (ep->flag_data == 0) {
+			cnt += snprintf(pbuf + cnt, limit - cnt, " =");
+			if ((data_len = ep->len_cap) >= DATA_MAX)
+				data_len = DATA_MAX;
+			for (i = 0; i < data_len; i++) {
+				if (i % 4 == 0) {
+					cnt += snprintf(pbuf + cnt, limit - cnt,
+					    " ");
+				}
+				cnt += snprintf(pbuf + cnt, limit - cnt,
+				    "%02x", data[i]);
+			}
+			cnt += snprintf(pbuf + cnt, limit - cnt, "\n");
+		} else {
+			cnt += snprintf(pbuf + cnt, limit - cnt,
+			    " %c\n", ep->flag_data);
+		}
+	} else {
+		cnt += snprintf(pbuf + cnt, limit - cnt, "\n");
+	}
+
+	printf("%s", printf_buf);
+}
+
+void parse_params(struct params *p, char **argv)
+{
+	char *arg;
+	long num;
+
+	memset(p, 0, sizeof(struct params));
+	p->data_size = 32;	/* Same as text API. */
+
+	while ((arg = *argv++) != NULL) {
+		if (arg[0] == '-') {
+			if (arg[1] == 0)
+				Usage();
+			if (arg[2] != 0)
+				Usage();
+			switch (arg[1]) {
+			case 'i':
+				if ((arg = *argv++) == NULL)
+					Usage();
+				if (strncmp(arg, "usb", 3) == 0)
+					arg += 3;
+				if (!isdigit(arg[0]))
+					Usage();
+				errno = 0;
+				num = strtol(arg, NULL, 10);
+				if (errno != 0)
+					Usage();
+				if (num < 0 || num >= 128) {
+					fprintf(stderr, TAG ": Bus number %ld"
+					   " is out of bounds\n", num);
+					exit(2);
+				}
+				p->ifnum = num;
+				break;
+			default:
+				Usage();
+			}
+		} else {
+			Usage();
+		}
+	}
+
+	if (p->ifnum == 0) {
+		fprintf(stderr, TAG ": Bus Zero is not supported yet\n");
+		exit(2);
+	}
+
+	if (p->devname == NULL) {
+		if ((p->devname = malloc(100)) == NULL) {
+			fprintf(stderr, TAG ": No core\n");
+			exit(1);
+		}
+		snprintf(p->devname, 100, "/dev/usbmon%d", p->ifnum);
+	}
+}
+
+void make_device(const struct params *p)
+{
+	int major;
+	dev_t dev;
+
+	major = find_major();
+	dev = makedev(major, p->ifnum);
+	if (mknod(p->devname, S_IFCHR|S_IRUSR|S_IWUSR, dev) != 0) {
+		fprintf(stderr, TAG ": Can't make device %s: %s\n",
+		    p->devname, strerror(errno));
+		exit(1);
+	}
+}
+
+int find_major(void)
+{
+	long num;
+	FILE *df;
+	enum { LEN = 50 };
+	char buff[LEN], c, *p;
+	char *major, *mname;
+
+	if ((df = fopen("/proc/devices", "r")) == NULL) {
+		fprintf(stderr, TAG ": Can't open /proc/devices\n");
+		exit(1);
+	}
+	num = -1;
+	while (fgets(buff, LEN, df) != NULL) {
+		p = buff;
+		major = NULL;
+		mname = NULL;
+		for (p = buff; (c = *p) != 0; p++) {
+			if (major == NULL) {
+				if (c != ' ') {
+					major = p;
+				}
+			} else if (mname == NULL) {
+				if (!isdigit(c) && c != ' ') {
+					mname = p;
+				}
+			} else {
+				if (c == '\n') {
+					*p = 0;
+					break;
+				}
+			}
+		}
+		if (major != NULL && mname != NULL) {
+			if (strcmp(mname, "usbmon") == 0) {
+				errno = 0;
+				num = strtol(major, NULL, 10);
+				if (errno != 0) {
+					fprintf(stderr, TAG ": Syntax error "
+					    "in /proc/devices\n");
+					exit(1);
+				}
+				break;
+			}
+		}
+	}
+	fclose(df);
+
+	if (num == -1) {
+		fprintf(stderr, TAG ": Can't find usbmon in /proc/devices\n");
+		exit(1);
+	}
+
+	if (num <= 0 || num > INT_MAX) {
+		fprintf(stderr, TAG ": Weird major %ld in /proc/devices\n",
+		    num);
+		exit(1);
+	}
+
+	return (int) num;
+}
+
+void Usage(void)
+{
+	fprintf(stderr, "Usage: usbmon [-i usbN]\n");
+	exit(2);
+}
