Hello,

I would like to share my last work to add a binary interface to usbmon.
This is still quite rough and does use the dreaded next_urb field into
the urb header structure, so it's not intended as a finished work. 

--
diff -upN linux-2.6.18-vanilla/drivers/usb/mon/Makefile 
linux-2.6.18-mon_mmap/drivers/usb/mon/Makefile
--- linux-2.6.18-vanilla/drivers/usb/mon/Makefile       2006-09-20 
05:42:06.000000000 +0200
+++ linux-2.6.18-mon_mmap/drivers/usb/mon/Makefile      2006-10-26 
11:30:35.000000000 +0200
@@ -2,7 +2,7 @@
 # Makefile for USB Core files and filesystem
 #
 
-usbmon-objs    := mon_main.o mon_stat.o mon_text.o mon_dma.o
+usbmon-objs    := mon_main.o mon_stat.o mon_text.o mon_dma.o mon_bindev.o
 
 # This does not use CONFIG_USB_MON because we want this to use a tristate.
 obj-$(CONFIG_USB)      += usbmon.o
diff -upN linux-2.6.18-vanilla/drivers/usb/mon/mon_bindev.c 
linux-2.6.18-mon_mmap/drivers/usb/mon/mon_bindev.c
--- linux-2.6.18-vanilla/drivers/usb/mon/mon_bindev.c   1970-01-01 
01:00:00.000000000 +0100
+++ linux-2.6.18-mon_mmap/drivers/usb/mon/mon_bindev.c  2006-11-06 
11:02:20.000000000 +0100
@@ -0,0 +1,775 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a binary format reader using a character device with dyanamically
+ * allocated major number
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/time.h>
+#include <linux/mutex.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/uio.h>
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_MAX  8
+
+/* ioctl macros */
+#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 mon_bin_urb_info)
+#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
+#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
+
+#define MON_RING_MIN_SIZE (16*1024)
+#define MON_RING_DFL_SIZE (64*1024)
+#define MON_RING_MAX_SIZE (1024*1024)
+
+#define MON_CHUNK_SHIFT 12
+#define MON_CHUNK_SIZE (1<<MON_CHUNK_SHIFT)
+#define MON_CHUNK_MASK (MON_CHUNK_SIZE - 1)
+
+#define MON_RING_PTR(rp, of) ((rp)->chunk_vec[(of) >> MON_CHUNK_SHIFT] + ((of) 
& MON_CHUNK_MASK))
+#define MON_RING_EMPTY(rp) ((rp)->write_pos == (rp)->rd->read_pos)
+
+struct mon_bin_hdr {
+    u64 id;
+    u8 type;        /* submit, complete, etc. */
+    u8 xfer_type;
+    u8 epnum;
+    u8 devnum;
+    u16 busnum;
+    u16 flags;      /* setup hdr presence */
+    s64 ts_sec;
+    s32 ts_usec;
+    s32 status;
+    u32 caplen;     /* length of data delivered to the application */
+    u32 len;        /* the actual length of URB data */
+    u32 next_urb;
+};
+
+struct mon_bin_urb_info {
+    struct mon_bin_hdr hdr;
+    char * data;
+};
+
+/* per file statistic */
+struct mon_bin_stats {
+    u32 queued;
+    u32 dropped;
+};
+
+/* this can be mmap from user space */
+struct mon_bin_ring_user {
+    u32 read_pos;
+};
+
+struct mon_bin_ring {
+    struct mon_bin_ring_user* rd; /* this can be memory mapped to user space*/
+    char** chunk_vec;
+    unsigned chunk_num;
+    unsigned size;
+    unsigned write_pos;
+    
+    struct mon_vec urb_data; /* store used for moving around current urb data*/
+};
+
+/* max number of USB bus supported */
+#define MON_BIN_MAX_MINOR 128
+
+#define MON_BIN_SETUP          0x1 /* setup hdr is present*/
+#define MON_BIN_SETUP_ZERO     0x2 /* setup buffer is not available */
+#define MON_BIN_DATA_ZERO      0x4 /* data buffer is not available */
+#define MON_BIN_ERROR          0x8
+#define MON_BIN_NO_MAP         0x10
+
+
+struct mon_bin_dev {
+    struct mon_bus *mbus;
+    struct cdev cdev;
+};
+
+struct mon_reader_bin {
+    int nevents;
+    int cnt_lost;
+    struct mon_reader r;    /* In C, parent class can be placed anywhere */
+    struct mon_bin_ring ring;
+    
+    wait_queue_head_t wait;
+    int vmas;
+};
+
+static int mon_bin_major = -1;
+static struct mon_bin_dev* mon_bin_devices[MON_BIN_MAX_MINOR];
+
+/* 
+ * Initialize data to handle 'vec_len' bytes of the ring buffer starting from 
position 'cur_pos'
+ */
+static void mon_bin_vec_init(const struct mon_bin_ring* rp, int cur_pos, int 
vec_len, 
+    struct mon_vec* data)
+{
+    struct kvec* buf;
+    int i = 0;
+       data->vec = data->store;
+    
+    for (buf = data->vec; (vec_len > 0); ++buf, ++i) {
+        unsigned cur_chunk = cur_pos >> MON_CHUNK_SHIFT;
+        unsigned cur_offset = cur_pos & MON_CHUNK_MASK;
+        unsigned cur_len = MON_CHUNK_SIZE - cur_offset;
+        cur_len = (cur_len > vec_len) ? vec_len : cur_len;
+        if (cur_chunk > rp->chunk_num) {
+            printk(KERN_ERR TAG ": consistency error on ring iovec: chunk %d 
max %d \n", 
+                cur_chunk, rp->chunk_num);
+            data->nsegs = 0;
+            return;
+        }
+        
+       buf->iov_base = rp->chunk_vec[cur_chunk] + cur_offset;
+       buf->iov_len = cur_len;
+       cur_pos += cur_len;
+       vec_len -= cur_len;
+    }
+    data->nsegs = i;
+}
+
+/*
+ * Copy len bytes from src to iovec dst. Update vec free segment counter and
+ * free vec pointer
+ */
+static void memcpy_vec(struct mon_vec* dst, const char* src, int len)
+{
+    struct kvec* buf= dst->vec;
+    while ((len>0) && (dst->nsegs>0)) {
+        int clen = (len > buf->iov_len) ? buf->iov_len: len;
+        
+        memcpy(buf->iov_base, src, clen);
+        src += clen;
+        buf->iov_base += clen;
+        buf->iov_len -= clen;
+        len -= clen;
+        if (buf->iov_len == 0) {
+            ++buf;
+            --dst->nsegs;
+        }
+    }
+    dst->vec = buf;
+}
+
+/*
+ * Try to allocate an mon_bin_hdr struct plus data_len bytes from circular 
buffer
+ * The header can't be splitted on different chunks and the whole data can't 
be 
+ * wrapped around the circular buffer, so when we are writing near the
+ * end of the circular buffer, we can leave some bytes unused and 'skip' to 
+ * the ring start, if more bytes are available there.
+ * The size of the allocated chunk is set into the header fields.
+ */
+static struct mon_bin_hdr * mon_bin_alloc(struct mon_reader_bin *rp, int 
data_len)
+{
+    struct mon_bin_hdr * ep;
+    int avail_for_data, urb_end, avail_in_chunk;
+    int end = rp->ring.size;
+    
+    /* check if enough free space is available for storing at least the 
header*/
+    if (rp->ring.rd->read_pos >  rp->ring.write_pos)
+        end = rp->ring.rd->read_pos;
+    avail_for_data = (end - rp->ring.write_pos) - 1 - sizeof(struct 
mon_bin_hdr);
+    if (avail_for_data < 0)
+        return 0;
+        
+    ep = (struct mon_bin_hdr *) MON_RING_PTR(&rp->ring,rp->ring.write_pos);
+    if (avail_for_data > data_len)
+        ep->caplen = data_len;
+    else
+        ep->caplen = avail_for_data;
+        
+    mon_bin_vec_init(&rp->ring, rp->ring.write_pos + sizeof(struct 
mon_bin_hdr), 
+        ep->caplen, &rp->ring.urb_data);
+        
+    /* check if next header will be stored on the same chunk */
+    urb_end = rp->ring.write_pos + ep->caplen + sizeof(struct mon_bin_hdr);
+    avail_in_chunk =  MON_CHUNK_SIZE - (urb_end & MON_CHUNK_MASK) - 1;
+    if (avail_in_chunk > sizeof(struct mon_bin_hdr))
+        rp->ring.write_pos = urb_end;
+    else
+        rp->ring.write_pos = ((urb_end & ~MON_CHUNK_MASK) + MON_CHUNK_SIZE) % 
rp->ring.size;
+    ep->next_urb = rp->ring.write_pos;
+    return ep;
+}
+
+static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
+    char ev_type)
+{
+    int pipein, data_len, total_len, data_avail, setup_bytes, data_bytes;
+    struct mon_bin_hdr *ep;
+    struct timeval ts;
+    int flags = 0;
+       
+    data_len = (ev_type == 'S') ? 
+        urb->transfer_buffer_length : urb->actual_length;
+    data_len = (data_len < 0) ? 0 : data_len;
+    total_len = data_len;
+
+    /* check for setup hdr availability */
+    setup_bytes = 0;
+    if (usb_pipecontrol(urb->pipe) && ev_type == 'S') {
+        total_len += SETUP_MAX;
+        if (urb->setup_packet == NULL) {
+            flags |= MON_BIN_SETUP_ZERO;
+            goto check_data;
+        }
+
+        setup_bytes = SETUP_MAX;
+    }
+
+check_data:
+    /* check for data availability */
+    data_bytes = 0;
+    pipein = usb_pipeint(urb->pipe);
+    if ((pipein && (ev_type == 'S')) ||        (!pipein && (ev_type == 'C')))
+        goto alloc;
+    if (urb->transfer_buffer == NULL) {
+        flags |= MON_BIN_DATA_ZERO;
+        goto alloc;
+    }
+    data_bytes = data_len;
+
+alloc:
+    if ((ep = mon_bin_alloc(rp, setup_bytes + data_bytes)) == NULL) {
+        rp->cnt_lost++;
+        return;
+    }
+
+    /* this is a single writer access, no lock shold be required */ 
+    ep->type = ev_type;
+    ep->xfer_type = usb_pipetype(urb->pipe);
+    ep->epnum = usb_pipeendpoint(urb->pipe);
+    ep->devnum = usb_pipedevice(urb->pipe);
+    do_gettimeofday(&ts);
+    ep->ts_sec = ts.tv_sec;
+    ep->ts_usec = ts.tv_usec;
+    ep->status = urb->status;
+    ep->len = total_len;
+    ep->status = urb->status;
+    data_avail = ep->caplen;
+
+    /* if dma copy fails we are going to whaste some pre allocate- bytes in the
+     * circular buffer, but this helps to keep things simple */
+    if (setup_bytes) {
+        setup_bytes = setup_bytes > data_avail ? data_avail : setup_bytes;
+        if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP) {
+            if (mon_dmapeek_vec(&rp->ring.urb_data, urb->setup_dma, 
setup_bytes) != 0) {
+                flags |= MON_BIN_NO_MAP;
+                setup_bytes = 0;
+                goto copy_data;
+            }
+        }
+        else
+            memcpy_vec(&rp->ring.urb_data, urb->setup_packet, setup_bytes);
+
+        data_avail -= setup_bytes;
+        flags |= MON_BIN_SETUP;
+    }
+
+copy_data:
+    if (data_bytes) {
+        data_bytes = data_bytes > data_avail ? data_avail : data_bytes;
+        if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+            if (mon_dmapeek_vec(&rp->ring.urb_data, urb->transfer_dma, 
data_bytes) != 0) {
+                data_bytes = 0;
+                goto out;
+            }
+           }
+        else 
+            memcpy_vec(&rp->ring.urb_data, urb->transfer_buffer, data_bytes);
+    }
+
+out:
+    ep->caplen = data_bytes+setup_bytes;
+    ep->flags = flags;
+    rp->nevents++;
+    wake_up(&rp->wait);
+}
+
+static void mon_bin_submit(void *data, struct urb *urb)
+{
+    struct mon_reader_bin *rp = data;
+    mon_bin_event(rp, urb, 'S');
+}
+
+static void mon_bin_complete(void *data, struct urb *urb)
+{
+    struct mon_reader_bin *rp = data;
+    mon_bin_event(rp, urb, 'C');
+}
+
+static void mon_bin_error(void *data, struct urb *urb, int error)
+{
+    struct timeval ts;
+    struct mon_bin_hdr* ep;
+    struct mon_reader_bin *rp = data;
+
+    /* we can be called from hardware IRQs */
+    if ((ep = mon_bin_alloc(rp, 0)) == NULL) {
+        rp->cnt_lost++;
+        return;
+    }
+
+    /* this is a single writer access, no lock shold be required */ 
+    ep->type = 'E';
+    ep->xfer_type = usb_pipetype(urb->pipe);
+    ep->epnum = usb_pipeendpoint(urb->pipe);
+    ep->devnum = usb_pipedevice(urb->pipe);
+    do_gettimeofday(&ts);
+    ep->ts_sec = ts.tv_sec;
+    ep->ts_usec = ts.tv_usec;
+    ep->len = 0;
+    ep->caplen = 0;
+    ep->status = error;
+    ep->flags = MON_BIN_ERROR;
+
+    rp->nevents++;
+    wake_up(&rp->wait);
+}
+
+/*
+ * Fetch next event from the circular buffer.
+ */
+struct mon_bin_hdr *mon_bin_fetch(struct mon_reader_bin *rp,
+    struct mon_bus *mbus)
+{
+    unsigned long flags;
+    struct mon_bin_hdr * ep = 0;
+
+    spin_lock_irqsave(&mbus->lock, flags);
+    if (MON_RING_EMPTY(&rp->ring)) 
+        goto out;
+
+    /* iovec must be initialized under the lock */
+    ep = (struct mon_bin_hdr *) MON_RING_PTR(&rp->ring,rp->ring.rd->read_pos);
+    mon_bin_vec_init(&rp->ring, rp->ring.rd->read_pos + sizeof(struct 
mon_bin_hdr),
+        ep->caplen, &rp->ring.urb_data);
+    rp->ring.rd->read_pos = ep->next_urb;
+    --rp->nevents;
+       
+out:   
+    spin_unlock_irqrestore(&mbus->lock, flags);
+    return ep;
+}
+
+/*
+ * Destroy ring buffer reader. Required lock is done out of here
+ */
+static void mon_bin_destroy_ring(struct mon_bin_ring* rp)
+{
+    int i;
+    if (rp->rd)
+        free_page((unsigned long)rp->rd);
+    if (rp->chunk_vec) {
+        for (i=0; i<rp->chunk_num; ++i)
+            if (rp->chunk_vec[i])
+                   kfree(rp->chunk_vec[i]);
+        kfree(rp->chunk_vec);
+    }
+    if (rp->urb_data.store)
+        kfree(rp->urb_data.store);
+}
+
+/* 
+ * Allocate and initialize as empty ring of specified size
+ */
+static int mon_bin_create_ring(struct mon_bin_ring* rp, int size)
+{
+    int i;
+
+    memset(rp, 0, sizeof(*rp));    
+    size = (size & (~MON_CHUNK_MASK)) + MON_CHUNK_SIZE;
+    if (size < MON_RING_MIN_SIZE || size > MON_RING_MAX_SIZE)
+        return -EINVAL;
+     
+    rp->size = size;
+    rp->chunk_num = size >> MON_CHUNK_SHIFT;
+    if ((rp->chunk_vec = kzalloc(sizeof(char*)*rp->chunk_num, GFP_KERNEL)) == 
NULL)
+        return -ENOMEM;
+        
+    if ((rp->urb_data.store = kmalloc(sizeof(struct kvec)*rp->chunk_num, 
+                                          GFP_KERNEL)) == NULL) {
+        mon_bin_destroy_ring(rp);
+        return -ENOMEM;
+    }
+        
+    if ((rp->rd = (struct mon_bin_ring_user *)__get_free_page(GFP_KERNEL)) == 
NULL) {
+        mon_bin_destroy_ring(rp);
+        return -ENOMEM;
+    }
+       
+    for (i=0; i<rp->chunk_num; ++i)
+        if ((rp->chunk_vec[i] = kmalloc(MON_CHUNK_SIZE, GFP_KERNEL)) == NULL) {
+            mon_bin_destroy_ring(rp);
+            return -ENOMEM;
+        }
+    rp->rd->read_pos = 0;
+    rp->write_pos = 0; 
+    return 0;
+}
+
+/*
+ * Create a new mon reader
+ */
+static int mon_bin_open(struct inode *inode, struct file *file)
+{
+    struct mon_bus *mbus;
+    struct mon_reader_bin *rp;
+    int rc;
+
+    struct usb_bus *ubus;
+    struct mon_bin_dev* dev = container_of(inode->i_cdev,
+                                 struct mon_bin_dev, cdev);
+
+    mutex_lock(&mon_lock);
+    mbus = dev->mbus;
+    ubus = mbus->u_bus;
+
+    rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL);
+    if (rp == NULL) {
+        rc = -ENOMEM;
+        goto err_alloc;
+    }
+
+    init_waitqueue_head(&rp->wait);
+
+    rp->r.m_bus = mbus;
+    rp->r.r_data = rp;
+    rp->r.rnf_submit = mon_bin_submit;
+    rp->r.rnf_error = mon_bin_error;
+    rp->r.rnf_complete = mon_bin_complete;
+
+    if ((rc = mon_bin_create_ring(&rp->ring, MON_RING_DFL_SIZE)) != 0)
+        goto err_alloc_pr;
+
+    file->private_data = rp;
+    mon_reader_add(mbus, &rp->r);
+
+    mutex_unlock(&mon_lock);
+    return 0;
+
+err_alloc_pr:
+    kfree(rp);
+err_alloc:
+    mutex_unlock(&mon_lock);
+    return rc;
+}
+
+/*
+ * Extract an event from list and copy it to user space, may block
+ */
+static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp, 
+        struct mon_bin_hdr __user *hdr, char __user *data, size_t nbytes)
+{
+    DECLARE_WAITQUEUE(waita, current);
+    struct mon_bin_hdr *ep;
+    int i;
+    int ret = 0;
+    struct mon_bus *mbus = rp->r.m_bus;
+
+    add_wait_queue(&rp->wait, &waita);
+    set_current_state(TASK_INTERRUPTIBLE);
+    while ((ep = mon_bin_fetch(rp, mbus)) == NULL) {
+        if (file->f_flags & O_NONBLOCK) {
+            set_current_state(TASK_RUNNING);
+            remove_wait_queue(&rp->wait, &waita);
+            return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
+        }
+        /*
+         * We do not count nwaiters, because ->release is supposed
+         * to be called when all openers are gone only.
+         */
+        schedule();
+        if (signal_pending(current)) {
+            remove_wait_queue(&rp->wait, &waita);
+            return -EINTR;
+        }
+        set_current_state(TASK_INTERRUPTIBLE);
+    }
+    set_current_state(TASK_RUNNING);
+    remove_wait_queue(&rp->wait, &waita);
+
+    /* check out how much URB data is present in this buffer*/
+    ep->caplen = (nbytes > ep->caplen) ? ep->caplen : nbytes;
+    if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
+        ret = -EFAULT;
+        goto out;
+    }
+
+    for (i=0; i < rp->ring.urb_data.nsegs; ++i) {
+        struct kvec* buf = &rp->ring.urb_data.vec[i];
+        if (copy_to_user(data, buf->iov_base, buf->iov_len)) {
+            ret = -EFAULT;
+            goto out;
+        }
+        data += buf->iov_len;
+    }
+
+out:
+    return ret;
+}
+
+static int mon_bin_release(struct inode *inode, struct file *file)
+{
+    struct mon_bus *mbus;
+    struct mon_reader_bin *rp = file->private_data;
+
+    mutex_lock(&mon_lock);
+    mbus = rp->r.m_bus;
+
+    if (mbus->nreaders <= 0) {
+        printk(KERN_ERR TAG ": consistency error on close\n");
+        mutex_unlock(&mon_lock);
+        return 0;
+    }
+    mon_reader_del(mbus, &rp->r);
+
+    mon_bin_destroy_ring(&rp->ring);
+    kfree(rp);
+
+    mutex_unlock(&mon_lock);
+    return 0;
+}
+
+static int mon_bin_read(struct file *file, char __user *buf,
+                               size_t nbytes, loff_t *ppos)
+{
+    if (nbytes < sizeof(struct mon_bin_hdr))
+        return -EFAULT;
+    return mon_bin_get_event(file, (struct mon_reader_bin *) 
file->private_data,
+        (struct mon_bin_hdr*) buf, buf+sizeof(struct mon_bin_hdr), 
+        nbytes - sizeof(struct mon_bin_hdr));
+}
+
+static int mon_bin_ioctl(struct inode *inode, struct file *file, 
+    unsigned int cmd, unsigned long arg)
+{
+    unsigned long flags;
+    struct mon_bin_urb_info info;
+    struct mon_reader_bin * rp;
+    struct mon_bin_stats* sp;
+    struct mon_bus* mbus;
+    struct mon_bin_ring ring;
+    int ret = 0;
+
+    /* basic sanity check */
+    if (!(rp = file->private_data))
+        return -ENODEV;
+    if (_IOC_TYPE(cmd) != MON_IOC_MAGIC)
+        return -ENOTTY;
+
+    rp = file->private_data;
+    mbus = rp->r.m_bus;
+
+    switch (cmd) {
+    case MON_IOCQ_URB_LEN:
+        spin_lock_irqsave(&mbus->lock, flags);
+        if (!MON_RING_EMPTY(&rp->ring)) {
+            struct mon_bin_hdr *ep = (struct mon_bin_hdr*) 
MON_RING_PTR(&rp->ring, rp->ring.rd->read_pos);
+            ret = ep->caplen;
+        }
+        spin_unlock_irqrestore(&mbus->lock, flags);
+        break;
+               
+    case MON_IOCQ_RING_SIZE:
+        ret = rp->ring.size;
+        break;
+               
+    case MON_IOCT_RING_SIZE:
+        spin_lock_irqsave(&mbus->lock, flags);
+        ret = mon_bin_create_ring(&ring, arg);
+        if (!ret) {
+            mon_bin_destroy_ring(&rp->ring);
+            rp->ring = ring;
+        }
+        spin_unlock_irqrestore(&mbus->lock, flags);
+        break;
+
+
+    case MON_IOCX_URB:
+        if (copy_from_user(&info, (struct mon_bin_urb_info __user *)arg,
+                                        sizeof(struct mon_bin_urb_info)))
+            return -EFAULT;
+
+        ret = mon_bin_get_event(file, rp, (struct mon_bin_hdr __user *)arg,
+            info.data, info.hdr.caplen);
+        break;
+
+    case MON_IOCG_STATS:
+        sp = (struct mon_bin_stats __user *)arg;
+        if (put_user(rp->cnt_lost, &sp->dropped))
+            return -EFAULT;
+        if (put_user(rp->nevents, &sp->queued))
+            return -EFAULT;
+        break;
+
+    default:
+        ret = -ENOTTY;
+        break;
+    }
+
+    return ret;
+}
+
+static unsigned int mon_bin_poll(struct file *filp, poll_table *wait)
+{
+    unsigned long flags;
+    struct mon_reader_bin *rp = filp->private_data;
+    struct mon_bus* mbus = rp->r.m_bus;
+    unsigned int mask = 0;
+
+    spin_lock_irqsave(&mbus->lock, flags);
+    poll_wait(filp, &rp->wait,  wait);
+    if (!MON_RING_EMPTY(&rp->ring))
+        mask |= POLLIN | POLLRDNORM;    /* readable */
+    spin_unlock_irqrestore(&mbus->lock, flags);
+    return mask;
+}
+
+/*
+ * open and close: just keep track of how many times the device is
+ * mapped, to avoid releasing it.
+ */
+
+static void mon_bin_vma_open(struct vm_area_struct *vma)
+{
+    struct mon_reader_bin *rp = vma->vm_private_data;
+
+    rp->vmas++;
+}
+
+static void mon_bin_vma_close(struct vm_area_struct *vma)
+{
+    struct mon_reader_bin *rp = vma->vm_private_data;
+
+    rp->vmas--;
+}
+
+/*
+ * map ring pages to user space
+ */
+struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
+                                unsigned long address, int *type)
+{
+    unsigned long offset, chunk_idx, chunk_offset;
+    struct mon_reader_bin *rp = vma->vm_private_data;
+    struct page *pageptr = NOPAGE_SIGBUS;
+
+    offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+    if (offset < PAGE_SIZE) {
+       pageptr = virt_to_page(rp->ring.rd);
+       goto found;
+    }
+    chunk_idx = (offset - PAGE_SIZE) >> MON_CHUNK_SHIFT;
+    if (chunk_idx > rp->ring.chunk_num)
+        goto out;
+    
+    chunk_offset = ((offset - PAGE_SIZE) & MON_CHUNK_MASK) & (~PAGE_MASK);
+    pageptr = virt_to_page(rp->ring.chunk_vec[chunk_idx] + chunk_offset);
+found:    
+    get_page(pageptr);
+    if (type)
+        *type = VM_FAULT_MINOR;
+out:
+    return pageptr;
+}
+
+struct vm_operations_struct mon_bin_vm_ops = {
+    .open =     mon_bin_vma_open,
+    .close =    mon_bin_vma_close,
+    .nopage =   mon_bin_vma_nopage,
+};
+
+
+int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+    /* don't do anything here: "nopage" will set up page table entries */
+    vma->vm_ops = &mon_bin_vm_ops;
+    vma->vm_flags |= VM_RESERVED;
+    vma->vm_private_data = filp->private_data;
+    mon_bin_vma_open(vma);
+    return 0;
+
+}
+
+struct file_operations mon_fops_binary = {
+    .owner =   THIS_MODULE,
+    .open =            mon_bin_open,
+    .llseek =  no_llseek,
+    .read =            mon_bin_read,
+    .poll =            mon_bin_poll,
+    .ioctl =   mon_bin_ioctl,
+    .mmap =    mon_bin_mmap,
+    .release = mon_bin_release,
+};
+
+#include "../core/hcd.h"
+
+int mon_bin_add(unsigned minor, struct mon_bus * mbus)
+{
+    struct mon_bin_dev* dev;
+    int devno = MKDEV(mon_bin_major, minor);
+    if ((minor >= MON_BIN_MAX_MINOR) || mon_bin_devices[minor])
+        return -EFAULT;
+
+    dev = kmalloc(sizeof(struct mon_bin_dev),  GFP_KERNEL);
+    if (!dev)
+        return -ENOMEM;
+    cdev_init(&dev->cdev, &mon_fops_binary);
+    dev->cdev.owner = THIS_MODULE;
+    dev->cdev.ops = &mon_fops_binary;
+    dev->mbus = mbus;
+    return cdev_add (&dev->cdev, devno, 1);
+}
+
+void mon_bin_del(unsigned minor)
+{
+    if ((minor >= MON_BIN_MAX_MINOR) || !mon_bin_devices[minor])
+        return;
+
+    cdev_del(&mon_bin_devices[minor]->cdev);
+    kfree(mon_bin_devices[minor]);
+    mon_bin_devices[minor] = 0;
+}
+
+int mon_bin_init(void)
+{
+    dev_t dev;
+    int err;
+
+    if ((err = alloc_chrdev_region(&dev, 0, MON_BIN_MAX_MINOR,
+                              "usb_mon_bin")) < 0)
+        return err;
+
+    memset(mon_bin_devices, 0, sizeof(mon_bin_devices));
+
+    mon_bin_major = MAJOR(dev);
+    return err;
+}
+
+void mon_bin_exit(void)
+{
+    unsigned i;
+    dev_t devno = MKDEV(mon_bin_major, 0);
+
+    for (i=0; i<MON_BIN_MAX_MINOR; ++i)
+        mon_bin_del(i);
+
+    /* free allocated main memory */
+    unregister_chrdev_region(devno, MON_BIN_MAX_MINOR);
+}
diff -upN linux-2.6.18-vanilla/drivers/usb/mon/mon_dma.c 
linux-2.6.18-mon_mmap/drivers/usb/mon/mon_dma.c
--- linux-2.6.18-vanilla/drivers/usb/mon/mon_dma.c      2006-09-20 
05:42:06.000000000 +0200
+++ linux-2.6.18-mon_mmap/drivers/usb/mon/mon_dma.c     2006-11-06 
11:02:35.000000000 +0100
@@ -9,6 +9,8 @@
 #include <linux/list.h>
 #include <linux/highmem.h>
 #include <asm/page.h>
+#include <asm/uaccess.h>
+#include <linux/uio.h>
 
 #include <linux/usb.h> /* Only needed for declarations in usb_mon.h */
 #include "usb_mon.h"
@@ -48,6 +50,56 @@ char mon_dmapeek(unsigned char *dst, dma
        local_irq_restore(flags);
        return 0;
 }
+
+char mon_dmapeek_vec(struct mon_vec* dst, dma_addr_t dma_addr, int len)
+{
+    struct page *pg;
+    unsigned long flags;
+    unsigned char *map;
+    unsigned char *ptr;
+       
+    struct kvec* buf = dst->vec;
+
+    /*
+     * We are called from hardware IRQs in case of callbacks.
+     * But we can be called from softirq or process context in case
+     * of submissions. In such case, we need to protect KM_IRQ0.
+     */
+    local_irq_save(flags);
+    while ((len > 0) && (dst->nsegs > 0)) {
+        /* compute number of bytes we are going to copy into this segment*/
+        int offset = dma_addr & (PAGE_SIZE-1);
+        int page_len = PAGE_SIZE - offset;
+        int copied = (len > page_len) ? page_len : len;
+        copied = (copied > buf->iov_len) ? buf->iov_len : copied;
+
+        /*
+         * On i386, a DMA handle is the "physical" address of a page.
+         * In other words, the bus address is equal to physical address.
+         * There is no IOMMU.
+         */
+        pg = phys_to_page(dma_addr);
+        map = kmap_atomic(pg, KM_IRQ0);
+        ptr = map + offset;
+               memcpy(buf->iov_base, ptr, copied);
+        kunmap_atomic(map, KM_IRQ0);
+               
+        offset = 0;
+        dma_addr += copied;
+        len -= copied;
+        buf->iov_len -= copied;
+        buf->iov_base += copied;
+        if (buf->iov_len == 0) {
+            ++buf;
+            --dst->nsegs;
+        }
+    } while (len > 0);
+       
+    dst->vec = buf;
+    local_irq_restore(flags);
+    return 0;    
+}
+
 #endif /* __i386__ */
 
 #ifndef MON_HAS_UNMAP
@@ -55,4 +107,9 @@ char mon_dmapeek(unsigned char *dst, dma
 {
        return 'D';
 }
+
+char mon_dmapeek_vec(struct mon_vec* dst, dma_addr_t dma_addr, int nsegs)
+{
+    return 'D';
+}
 #endif
diff -upN linux-2.6.18-vanilla/drivers/usb/mon/mon_main.c 
linux-2.6.18-mon_mmap/drivers/usb/mon/mon_main.c
--- linux-2.6.18-vanilla/drivers/usb/mon/mon_main.c     2006-09-20 
05:42:06.000000000 +0200
+++ linux-2.6.18-mon_mmap/drivers/usb/mon/mon_main.c    2006-11-06 
11:03:25.000000000 +0100
@@ -214,6 +214,7 @@ static void mon_bus_remove(struct usb_bu
        list_del(&mbus->bus_link);
        debugfs_remove(mbus->dent_t);
        debugfs_remove(mbus->dent_s);
+       mon_bin_del(ubus->busnum);
 
        mon_dissolve(mbus, ubus);
        kref_put(&mbus->ref, mon_bus_drop);
@@ -319,12 +320,17 @@ static void mon_bus_init(struct dentry *
        if (d == NULL)
                goto err_create_s;
        mbus->dent_s = d;
+       
+       if (mon_bin_add(ubus->busnum, mbus) < 0)
+               goto err_create_b;
 
        mutex_lock(&mon_lock);
        list_add_tail(&mbus->bus_link, &mon_buses);
        mutex_unlock(&mon_lock);
        return;
 
+err_create_b:
+       debugfs_remove(mbus->dent_s);
 err_create_s:
 err_print_s:
        debugfs_remove(mbus->dent_t);
@@ -358,6 +364,7 @@ static int __init mon_init(void)
        }
        // MOD_INC_USE_COUNT(which_module?);
 
+       mon_bin_init();
        usb_register_notify(&mon_nb);
 
        mutex_lock(&usb_bus_list_lock);
@@ -402,6 +409,7 @@ static void __exit mon_exit(void)
        }
        mutex_unlock(&mon_lock);
 
+       mon_bin_exit();
        debugfs_remove(mon_dir);
 }
 
diff -upN linux-2.6.18-vanilla/drivers/usb/mon/mon_text.c 
linux-2.6.18-mon_mmap/drivers/usb/mon/mon_text.c
--- linux-2.6.18-vanilla/drivers/usb/mon/mon_text.c     2006-09-20 
05:42:06.000000000 +0200
+++ linux-2.6.18-mon_mmap/drivers/usb/mon/mon_text.c    2006-10-26 
11:30:35.000000000 +0200
@@ -457,4 +457,3 @@ static void mon_text_ctor(void *mem, kme
         */
        memset(mem, 0xe5, sizeof(struct mon_event_text));
 }
-
diff -upN linux-2.6.18-vanilla/drivers/usb/mon/usb_mon.h 
linux-2.6.18-mon_mmap/drivers/usb/mon/usb_mon.h
--- linux-2.6.18-vanilla/drivers/usb/mon/usb_mon.h      2006-09-20 
05:42:06.000000000 +0200
+++ linux-2.6.18-mon_mmap/drivers/usb/mon/usb_mon.h     2006-11-03 
09:07:34.000000000 +0100
@@ -44,12 +44,24 @@ struct mon_reader {
        void (*rnf_complete)(void *data, struct urb *urb);
 };
 
+struct mon_vec {
+    struct kvec* store; 
+    struct kvec* vec; /* ptr to first free item in store*/
+    unsigned nsegs; /* number of free items in store*/
+};
+
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
 void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
+    
+int mon_bin_init(void);
+void mon_bin_exit(void);
+int mon_bin_add(unsigned minor, struct mon_bus * mbus);
+void mon_bin_del(unsigned minor);
 
 /*
  */
 extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
+extern char mon_dmapeek_vec(struct mon_vec* dst, dma_addr_t dma_addr, int len);
 
 extern struct mutex mon_lock;
 



-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to