#include <linux/usb.h> /* Only needed for declarations in usb_mon.h */
 #include "usb_mon.h"
 
-#ifdef __i386__                /* CONFIG_ARCH_I386 does not exit */
+/*
+ * PC-compatibles, are, fortunately, sufficiently cache-coherent for this.
+ */
+#if defined(__i386__) || defined(__x86_64__) /* CONFIG_ARCH_I386 doesn't exit */
 #define MON_HAS_UNMAP 1
 
 #define phys_to_page(phys)     pfn_to_page((phys) >> PAGE_SHIFT)
 
        if (mbus->nreaders == 0)
                goto out_locked;
 
+       mbus->cnt_events++;
        list_for_each (pos, &mbus->r_list) {
                r = list_entry(pos, struct mon_reader, r_link);
                r->rnf_submit(r->r_data, urb);
        }
 
        spin_lock_irqsave(&mbus->lock, flags);
+       mbus->cnt_events++;
        list_for_each (pos, &mbus->r_list) {
                r = list_entry(pos, struct mon_reader, r_link);
                r->rnf_complete(r->r_data, urb);
 
 /*
  * Stop monitoring.
- * Obviously this must be well locked, so no need to play with mb's.
  */
 static void mon_stop(struct mon_bus *mbus)
 {
 
        mbus = inode->u.generic_ip;
 
        sp->slen = snprintf(sp->str, STAT_BUF_SIZE,
-           "nreaders %d text_lost %u\n",
-           mbus->nreaders, mbus->cnt_text_lost);
+           "nreaders %d events %u text_lost %u\n",
+           mbus->nreaders, mbus->cnt_events, mbus->cnt_text_lost);
 
        file->private_data = sp;
        return 0;
 
 
 /*
  * This limit exists to prevent OOMs when the user process stops reading.
+ * If usbmon were available to unprivileged processes, it might be open
+ * to a local DoS. But we have to keep to root in order to prevent
+ * password sniffing from HID devices.
  */
-#define EVENT_MAX  25
+#define EVENT_MAX  (2*PAGE_SIZE / sizeof(struct mon_event_text))
 
-#define PRINTF_DFL  130
+#define PRINTF_DFL  160
 
 struct mon_event_text {
        struct list_head e_link;
         * number of corner cases, but it seems that the following is
         * more or less safe.
         *
-        * We do not even try to look transfer_buffer, because it can
+        * We do not even try to look at transfer_buffer, because it can
         * contain non-NULL garbage in case the upper level promised to
         * set DMA for the HCD.
         */
 
        struct kref ref;                /* Under mon_lock */
 
        /* Stats */
+       unsigned int cnt_events;
        unsigned int cnt_text_lost;
 };