On Wed, 28 Mar 2007 10:33:23 +0200, [EMAIL PROTECTED] wrote:
> on 27/03/07 20:25 Pete Zaitcev wrote:
> > [ISO packet descriptor]
> > My current patch (see below) puts them
> > into data
> There is a potential issue with the byte ordering, from an application point
> of view. With the current upstream binary api, the event header is in host
> byte order, except for the setup header (in BE byte order). The urb data is
> BE. It would be nice to keep the byte alignment similar also for ISO
> descriptors data.
As you probably know from our discussions with Jon Smirl, I do not
agree with this model. The binary usbmon API is not a wire protocol.
It's more of a set of procedure calls, only with a complication of
crossing a protection boundary. This is why all fields recognized by
usbmon's kernel code are in the host byte order. The setup packet
is treated as an array of bytes by the usbmon, although of course we
know that it has a structure. If usbmon delivered a structure, it
would've been in host byte order.
> > [hdeader size]
> > So, I wanted to expand the main record from 48 to 64 bytes.
> > This is compatible with mmap, but the interface has to be made
> > "modal"
>
> I would like to avoid such situation, but the alternative is not so nice.
> Anyway please give a look to the patch below: I try to add all the extended
> information re-using the setup header and adding extra events for the ISO
> packet descriptors (one event with all the descriptor, like your patch).
> This patch is only about the binary api extenstion (It's a differential
> patch against latest bus 0 implementation as seen on ML).
I looked and liked what I saw at first. However, it seems that even
with your patch it's not possible to stuff everything into the old
48-byte header. Therefore, it is still necessary to change the header size.
In short, I would like to strong-arm you into accepting what I have. :-)
> - char flag_setup;
> + char flag_hdr;
I don't think this is fully compatible.
> unsigned int len_cap; /* Delivered length */
> - unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
> + union {
> + unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
> + struct {
> + int interval;
> + unsigned int xfer_flags;
> + } compl_hdr; /* For C/E-Type */
> + struct {
> + int start_frame;
> + int number_of_packets;
> + } iso_hdr; /* For ISO P-Type */
> + };
The problem here is, xfer_flags are needed for both submission and
callback. We know that they have to stay the same, but it's safer to
have them available as is.
> +/* create extra event for ISO frames info; must be called with rp->b_lock
> hold */
> +static void mon_bin_iso_event(struct mon_reader_bin *rp, struct urb *urb,
> + struct timeval* ts)
> +{
> + int i,datalen;
> + unsigned int offset;
> + struct mon_bin_hdr *ep;
> +
> + datalen = urb->number_of_packets * sizeof(struct
> usb_iso_packet_descriptor);
> + offset = mon_buff_area_alloc_contiguous(rp, PKT_SIZE + datalen);
> .....
This is the nicest part of your patch. But on second thought, it does not
offer a decisive advantage over what I've done. Sure, my arithmetic with
two sizes is somewhat convoluted, but yours looks simpler than it should be.
The usbmon cannot trust number_of_packets, because it's a debugging tool.
Also, what about this:
> + ep->iso_hdr.number_of_packets = cpu_to_be32(urb->number_of_packets);
> + for (i = 0; i< ep->iso_hdr.number_of_packets; ++i) {
> + struct usb_iso_packet_descriptor* pd = MON_OFF2DSC(rp, offset);
The i is host endian and the cycle limit is big endian. Looks like a bug.
Anyway, I've dropped the mode ioctl, but otherwise left what I had intact.
Attached is the current tree, diffed against Greg's.
-- Pete
diff -urp -X dontdiff linux-2.6.21-rc6-git2-gregkh/drivers/usb/mon/mon_bin.c
linux-2.6.21-mon/drivers/usb/mon/mon_bin.c
--- linux-2.6.21-rc6-git2-gregkh/drivers/usb/mon/mon_bin.c 2007-04-10
23:31:51.000000000 -0700
+++ linux-2.6.21-mon/drivers/usb/mon/mon_bin.c 2007-04-10 23:17:45.000000000
-0700
@@ -4,7 +4,7 @@
* This is a binary format reader.
*
* Copyright (C) 2006 Paolo Abeni ([EMAIL PROTECTED])
- * Copyright (C) 2006 Pete Zaitcev ([EMAIL PROTECTED])
+ * Copyright (C) 2006,2007 Pete Zaitcev ([EMAIL PROTECTED])
*/
#include <linux/kernel.h>
@@ -36,9 +36,12 @@
#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
+/* #9 was MON_IOCT_SETAPI */
+#define MON_IOCX_GETX _IOW(MON_IOC_MAGIC, 10, struct mon_bin_get)
#ifdef CONFIG_COMPAT
#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32)
#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32)
+#define MON_IOCX_GETX32 _IOW(MON_IOC_MAGIC, 10, struct mon_bin_get32)
#endif
/*
@@ -90,7 +93,29 @@ struct mon_bin_hdr {
int status;
unsigned int len_urb; /* Length of data (submitted or actual) */
unsigned int len_cap; /* Delivered length */
- unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
+ union {
+ unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
+ struct iso_rec {
+ int error_count;
+ int numdesc;
+ } iso;
+ } s;
+ int interval;
+ int start_frame;
+ unsigned int xfer_flags;
+ unsigned int ndesc; /* Actual number of ISO descriptors */
+};
+
+/*
+ * ISO vector, packed into the head of data stream.
+ * This has to take 16 bytes to make sure that the end of buffer
+ * wrap is not happening in the middle of a descriptor.
+ */
+struct mon_bin_isodesc {
+ int iso_status;
+ unsigned int iso_off;
+ unsigned int iso_len;
+ u32 _pad;
};
/* per file statistic */
@@ -100,7 +125,7 @@ struct mon_bin_stats {
};
struct mon_bin_get {
- struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */
+ struct mon_bin_hdr __user *hdr; /* Can be 48 bytes or 64. */
void __user *data;
size_t alloc; /* Length of data (can be zero) */
};
@@ -129,6 +154,11 @@ struct mon_bin_mfetch32 {
#define PKT_ALIGN 64
#define PKT_SIZE 64
+#define PKT_SZ_API0 48 /* API 0 (2.6.20) size */
+#define PKT_SZ_API1 64 /* API 1 size: extra fields */
+
+#define ISODESC_MAX 128 /* Same number as usbfs allows, 2048 bytes. */
+
/* max number of USB bus supported */
#define MON_BIN_MAX_MINOR 128
@@ -172,6 +202,7 @@ static inline struct mon_bin_hdr *MON_OF
#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0)
+static struct class *mon_bin_class;
static dev_t mon_bin_dev0;
static struct cdev mon_bin_cdev;
@@ -353,11 +384,10 @@ static inline char mon_bin_get_setup(uns
const struct urb *urb, char ev_type)
{
- if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
- return '-';
-
- if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+ if (urb->dev->bus->uses_dma &&
+ (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
+ }
if (urb->setup_packet == NULL)
return 'Z';
@@ -369,7 +399,8 @@ static char mon_bin_get_data(const struc
unsigned int offset, struct urb *urb, unsigned int length)
{
- if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+ if (urb->dev->bus->uses_dma &&
+ (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
return 0;
}
@@ -381,6 +412,26 @@ static char mon_bin_get_data(const struc
return 0;
}
+static void mon_bin_get_isodesc(const struct mon_reader_bin *rp,
+ unsigned int offset, struct urb *urb, char ev_type, unsigned int ndesc)
+{
+ struct mon_bin_isodesc *dp;
+ struct usb_iso_packet_descriptor *fp;
+
+ fp = urb->iso_frame_desc;
+ while (ndesc-- != 0) {
+ dp = (struct mon_bin_isodesc *)
+ (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE);
+ dp->iso_status = fp->status;
+ dp->iso_off = fp->offset;
+ dp->iso_len = (ev_type == 'S') ? fp->length : fp->actual_length;
+ dp->_pad = 0;
+ if ((offset += sizeof(struct mon_bin_isodesc)) >= rp->b_size)
+ offset = 0;
+ fp++;
+ }
+}
+
static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
char ev_type)
{
@@ -389,6 +440,7 @@ static void mon_bin_event(struct mon_rea
unsigned int urb_length;
unsigned int offset;
unsigned int length;
+ unsigned int ndesc, lendesc;
struct mon_bin_hdr *ep;
char data_tag = 0;
@@ -399,6 +451,19 @@ static void mon_bin_event(struct mon_rea
/*
* Find the maximum allowable length, then allocate space.
*/
+ if (usb_pipeisoc(urb->pipe)) {
+ if (urb->number_of_packets < 0) {
+ ndesc = 0;
+ } else if (urb->number_of_packets >= ISODESC_MAX) {
+ ndesc = ISODESC_MAX;
+ } else {
+ ndesc = urb->number_of_packets;
+ }
+ } else {
+ ndesc = 0;
+ }
+ lendesc = ndesc*sizeof(struct mon_bin_isodesc);
+
urb_length = (ev_type == 'S') ?
urb->transfer_buffer_length : urb->actual_length;
length = urb_length;
@@ -418,10 +483,12 @@ static void mon_bin_event(struct mon_rea
}
}
- if (rp->mmap_active)
- offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE);
- else
- offset = mon_buff_area_alloc(rp, length + PKT_SIZE);
+ if (rp->mmap_active) {
+ offset = mon_buff_area_alloc_contiguous(rp,
+ length + PKT_SIZE + lendesc);
+ } else {
+ offset = mon_buff_area_alloc(rp, length + PKT_SIZE + lendesc);
+ }
if (offset == ~0) {
rp->cnt_lost++;
spin_unlock_irqrestore(&rp->b_lock, flags);
@@ -440,15 +507,37 @@ static void mon_bin_event(struct mon_rea
/* We use the fact that usb_pipein() returns 0x80 */
ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
ep->devnum = usb_pipedevice(urb->pipe);
- ep->busnum = rp->r.m_bus->u_bus->busnum;
+ ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->ts_sec = ts.tv_sec;
ep->ts_usec = ts.tv_usec;
ep->status = urb->status;
ep->len_urb = urb_length;
- ep->len_cap = length;
+ ep->len_cap = length + lendesc;
+ ep->xfer_flags = urb->transfer_flags;
+
+ if (usb_pipeint(urb->pipe)) {
+ ep->interval = urb->interval;
+ } else if (usb_pipeisoc(urb->pipe)) {
+ ep->interval = urb->interval;
+ ep->start_frame = urb->start_frame;
+ ep->s.iso.error_count = urb->error_count;
+ ep->s.iso.numdesc = urb->number_of_packets;
+ }
+
+ if (usb_pipecontrol(urb->pipe) && ev_type == 'S') {
+ ep->flag_setup = mon_bin_get_setup(ep->s.setup, urb, ev_type);
+ } else {
+ ep->flag_setup = '-';
+ }
+
+ if (ndesc != 0) {
+ ep->ndesc = ndesc;
+ mon_bin_get_isodesc(rp, offset, urb, ev_type, ndesc);
+ if ((offset += lendesc) >= rp->b_size)
+ offset -= rp->b_size;
+ }
- ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type);
if (length != 0) {
ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */
@@ -500,7 +589,7 @@ static void mon_bin_error(void *data, st
/* We use the fact that usb_pipein() returns 0x80 */
ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
ep->devnum = usb_pipedevice(urb->pipe);
- ep->busnum = rp->r.m_bus->u_bus->busnum;
+ ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->status = error;
@@ -515,7 +604,6 @@ static void mon_bin_error(void *data, st
static int mon_bin_open(struct inode *inode, struct file *file)
{
struct mon_bus *mbus;
- struct usb_bus *ubus;
struct mon_reader_bin *rp;
size_t size;
int rc;
@@ -525,7 +613,7 @@ static int mon_bin_open(struct inode *in
mutex_unlock(&mon_lock);
return -ENODEV;
}
- if ((ubus = mbus->u_bus) == NULL) {
+ if (mbus != &mon_bus0 && mbus->u_bus == NULL) {
printk(KERN_ERR TAG ": consistency error on open\n");
mutex_unlock(&mon_lock);
return -ENODEV;
@@ -539,7 +627,6 @@ static int mon_bin_open(struct inode *in
spin_lock_init(&rp->b_lock);
init_waitqueue_head(&rp->b_wait);
mutex_init(&rp->fetch_lock);
-
rp->b_size = BUFF_DFL;
size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE);
@@ -578,7 +665,8 @@ err_alloc:
* Returns zero or error.
*/
static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
- struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes)
+ struct mon_bin_hdr __user *hdr, unsigned int hdrbytes,
+ void __user *data, unsigned int nbytes)
{
unsigned long flags;
struct mon_bin_hdr *ep;
@@ -595,7 +683,7 @@ static int mon_bin_get_event(struct file
ep = MON_OFF2HDR(rp, rp->b_out);
- if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
+ if (copy_to_user(hdr, ep, hdrbytes)) {
mutex_unlock(&rp->fetch_lock);
return -EFAULT;
}
@@ -643,6 +731,7 @@ static ssize_t mon_bin_read(struct file
size_t nbytes, loff_t *ppos)
{
struct mon_reader_bin *rp = file->private_data;
+ unsigned int hdrbytes = PKT_SZ_API0;
unsigned long flags;
struct mon_bin_hdr *ep;
unsigned int offset;
@@ -660,8 +749,8 @@ static ssize_t mon_bin_read(struct file
ep = MON_OFF2HDR(rp, rp->b_out);
- if (rp->b_read < sizeof(struct mon_bin_hdr)) {
- step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read);
+ if (rp->b_read < hdrbytes) {
+ step_len = min(nbytes, (size_t)(hdrbytes - rp->b_read));
ptr = ((char *)ep) + rp->b_read;
if (step_len && copy_to_user(buf, ptr, step_len)) {
mutex_unlock(&rp->fetch_lock);
@@ -673,10 +762,10 @@ static ssize_t mon_bin_read(struct file
done += step_len;
}
- if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
+ if (rp->b_read >= hdrbytes) {
step_len = min(nbytes, (size_t)ep->len_cap);
offset = rp->b_out + PKT_SIZE;
- offset += rp->b_read - sizeof(struct mon_bin_hdr);
+ offset += rp->b_read - hdrbytes;
if (offset >= rp->b_size)
offset -= rp->b_size;
if (copy_from_buf(rp, offset, buf, step_len)) {
@@ -692,7 +781,7 @@ static ssize_t mon_bin_read(struct file
/*
* Check if whole packet was read, and if so, jump to the next one.
*/
- if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) {
+ if (rp->b_read >= hdrbytes + ep->len_cap) {
spin_lock_irqsave(&rp->b_lock, flags);
mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
spin_unlock_irqrestore(&rp->b_lock, flags);
@@ -891,6 +980,7 @@ static int mon_bin_ioctl(struct inode *i
break;
case MON_IOCX_GET:
+ case MON_IOCX_GETX:
{
struct mon_bin_get getb;
@@ -900,22 +990,25 @@ static int mon_bin_ioctl(struct inode *i
if (getb.alloc > 0x10000000) /* Want to cast to u32 */
return -EINVAL;
- ret = mon_bin_get_event(file, rp,
- getb.hdr, getb.data, (unsigned int)getb.alloc);
+ ret = mon_bin_get_event(file, rp, getb.hdr,
+ (cmd == MON_IOCX_GET)? PKT_SZ_API0: PKT_SZ_API1,
+ getb.data, (unsigned int)getb.alloc);
}
break;
#ifdef CONFIG_COMPAT
- case MON_IOCX_GET32: {
+ case MON_IOCX_GET32:
+ case MON_IOCX_GETX32:
+ {
struct mon_bin_get32 getb;
if (copy_from_user(&getb, (void __user *)arg,
sizeof(struct mon_bin_get32)))
return -EFAULT;
- ret = mon_bin_get_event(file, rp,
- compat_ptr(getb.hdr32), compat_ptr(getb.data32),
- getb.alloc32);
+ ret = mon_bin_get_event(file, rp, compat_ptr(getb.hdr32),
+ (cmd == MON_IOCX_GET32)? PKT_SZ_API0: PKT_SZ_API1,
+ compat_ptr(getb.data32), getb.alloc32);
}
break;
#endif
@@ -1142,10 +1235,38 @@ static void mon_free_buff(struct mon_pgm
free_page((unsigned long) map[n].ptr);
}
+int mon_bin_add(struct mon_bus *mbus, int busnum)
+{
+ struct device *dev;
+ unsigned minor = busnum;
+
+ if (minor >= MON_BIN_MAX_MINOR)
+ return 0;
+
+ dev = device_create(mon_bin_class, NULL,
+ MKDEV(MAJOR(mon_bin_dev0), minor), "usbmon%d", minor);
+ if (IS_ERR(dev))
+ return 0;
+
+ mbus->classdev = dev;
+ return 1;
+}
+
+void mon_bin_del(struct mon_bus *mbus)
+{
+ device_destroy(mon_bin_class, mbus->classdev->devt);
+}
+
int __init mon_bin_init(void)
{
int rc;
+ mon_bin_class = class_create(THIS_MODULE, "usbmon");
+ if (IS_ERR(mon_bin_class)) {
+ rc = PTR_ERR(mon_bin_class);
+ goto err_class;
+ }
+
rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
if (rc < 0)
goto err_dev;
@@ -1162,6 +1283,8 @@ int __init mon_bin_init(void)
err_add:
unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
err_dev:
+ class_destroy(mon_bin_class);
+err_class:
return rc;
}
@@ -1169,4 +1292,5 @@ void mon_bin_exit(void)
{
cdev_del(&mon_bin_cdev);
unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+ class_destroy(mon_bin_class);
}
diff -urp -X dontdiff linux-2.6.21-rc6-git2-gregkh/drivers/usb/mon/mon_main.c
linux-2.6.21-mon/drivers/usb/mon/mon_main.c
--- linux-2.6.21-rc6-git2-gregkh/drivers/usb/mon/mon_main.c 2007-04-10
23:31:51.000000000 -0700
+++ linux-2.6.21-mon/drivers/usb/mon/mon_main.c 2007-03-05 13:14:18.000000000
-0800
@@ -16,8 +16,6 @@
#include "usb_mon.h"
#include "../core/hcd.h"
-static void mon_submit(struct usb_bus *ubus, struct urb *urb);
-static void mon_complete(struct usb_bus *ubus, struct urb *urb);
static void mon_stop(struct mon_bus *mbus);
static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
static void mon_bus_drop(struct kref *r);
@@ -25,6 +23,7 @@ static void mon_bus_init(struct usb_bus
DEFINE_MUTEX(mon_lock);
+struct mon_bus mon_bus0; /* Pseudo bus meaning "all buses" */
static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
/*
@@ -35,22 +34,19 @@ static LIST_HEAD(mon_buses); /* All bus
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r)
{
unsigned long flags;
- struct usb_bus *ubus;
+ struct list_head *p;
spin_lock_irqsave(&mbus->lock, flags);
if (mbus->nreaders == 0) {
- ubus = mbus->u_bus;
- if (ubus->monitored) {
- /*
- * Something is really broken, refuse to go on and
- * possibly corrupt ops pointers or worse.
- */
- printk(KERN_ERR TAG ": bus %d is already monitored\n",
- ubus->busnum);
- spin_unlock_irqrestore(&mbus->lock, flags);
- return;
+ if (mbus == &mon_bus0) {
+ list_for_each (p, &mon_buses) {
+ struct mon_bus *m1;
+ m1 = list_entry(p, struct mon_bus, bus_link);
+ m1->u_bus->monitored = 1;
+ }
+ } else {
+ mbus->u_bus->monitored = 1;
}
- ubus->monitored = 1;
}
mbus->nreaders++;
list_add_tail(&r->r_link, &mbus->r_list);
@@ -80,77 +76,79 @@ void mon_reader_del(struct mon_bus *mbus
/*
*/
-static void mon_submit(struct usb_bus *ubus, struct urb *urb)
+static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb)
{
- struct mon_bus *mbus;
unsigned long flags;
struct list_head *pos;
struct mon_reader *r;
- mbus = ubus->mon_bus;
- if (mbus == NULL)
- goto out_unlocked;
-
spin_lock_irqsave(&mbus->lock, flags);
- 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_unlock_irqrestore(&mbus->lock, flags);
return;
+}
-out_locked:
- spin_unlock_irqrestore(&mbus->lock, flags);
-out_unlocked:
- return;
+static void mon_submit(struct usb_bus *ubus, struct urb *urb)
+{
+ struct mon_bus *mbus;
+
+ if ((mbus = ubus->mon_bus) != NULL)
+ mon_bus_submit(mbus, urb);
+ mon_bus_submit(&mon_bus0, urb);
}
/*
*/
-static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
+static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int
error)
{
- struct mon_bus *mbus;
unsigned long flags;
struct list_head *pos;
struct mon_reader *r;
- mbus = ubus->mon_bus;
- if (mbus == NULL)
- goto out_unlocked;
-
spin_lock_irqsave(&mbus->lock, flags);
- 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_error(r->r_data, urb, error);
}
-
spin_unlock_irqrestore(&mbus->lock, flags);
return;
+}
-out_locked:
- spin_unlock_irqrestore(&mbus->lock, flags);
-out_unlocked:
- return;
+static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
+{
+ struct mon_bus *mbus;
+
+ if ((mbus = ubus->mon_bus) != NULL)
+ mon_bus_submit_error(mbus, urb, error);
+ mon_bus_submit_error(&mon_bus0, urb, error);
}
/*
*/
-static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
{
- struct mon_bus *mbus;
unsigned long flags;
struct list_head *pos;
struct mon_reader *r;
+ 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);
+ }
+ spin_unlock_irqrestore(&mbus->lock, flags);
+}
+
+static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+{
+ struct mon_bus *mbus;
+
mbus = ubus->mon_bus;
if (mbus == NULL) {
/*
@@ -162,13 +160,8 @@ static void mon_complete(struct usb_bus
return;
}
- 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);
- }
- spin_unlock_irqrestore(&mbus->lock, flags);
+ mon_bus_complete(mbus, urb);
+ mon_bus_complete(&mon_bus0, urb);
}
/* int (*unlink_urb) (struct urb *urb, int status); */
@@ -179,14 +172,26 @@ static void mon_complete(struct usb_bus
static void mon_stop(struct mon_bus *mbus)
{
struct usb_bus *ubus = mbus->u_bus;
+ struct list_head *p;
- /*
- * A stop can be called for a dissolved mon_bus in case of
- * a reader staying across an rmmod foo_hcd.
- */
- if (ubus != NULL) {
- ubus->monitored = 0;
- mb();
+ if (mbus == &mon_bus0) {
+ list_for_each (p, &mon_buses) {
+ mbus = list_entry(p, struct mon_bus, bus_link);
+ /*
+ * We do not change nreaders here, so rely on mon_lock.
+ */
+ if (mbus->nreaders == 0 && (ubus = mbus->u_bus) != NULL)
+ ubus->monitored = 0;
+ }
+ } else {
+ /*
+ * A stop can be called for a dissolved mon_bus in case of
+ * a reader staying across an rmmod foo_hcd, so test ->u_bus.
+ */
+ if (mon_bus0.nreaders == 0 && (ubus = mbus->u_bus) != NULL) {
+ ubus->monitored = 0;
+ mb();
+ }
}
}
@@ -199,6 +204,10 @@ static void mon_stop(struct mon_bus *mbu
static void mon_bus_add(struct usb_bus *ubus)
{
mon_bus_init(ubus);
+ mutex_lock(&mon_lock);
+ if (mon_bus0.nreaders != 0)
+ ubus->monitored = 1;
+ mutex_unlock(&mon_lock);
}
/*
@@ -212,6 +221,8 @@ static void mon_bus_remove(struct usb_bu
list_del(&mbus->bus_link);
if (mbus->text_inited)
mon_text_del(mbus);
+ if (mbus->bin_inited)
+ mon_bin_del(mbus);
mon_dissolve(mbus, ubus);
kref_put(&mbus->ref, mon_bus_drop);
@@ -250,12 +261,7 @@ static struct usb_mon_operations mon_ops
static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
{
- /*
- * Never happens, but...
- */
if (ubus->monitored) {
- printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n",
- ubus->busnum);
ubus->monitored = 0;
mb();
}
@@ -263,6 +269,8 @@ static void mon_dissolve(struct mon_bus
ubus->mon_bus = NULL;
mbus->u_bus = NULL;
mb();
+
+ /* We want synchronize_irq() here, but that needs an argument. */
}
/*
@@ -295,10 +303,9 @@ static void mon_bus_init(struct usb_bus
*/
mbus->u_bus = ubus;
ubus->mon_bus = mbus;
- mbus->uses_dma = ubus->uses_dma;
- mbus->text_inited = mon_text_add(mbus, ubus);
- // mon_bin_add(...)
+ mbus->text_inited = mon_text_add(mbus, ubus->busnum);
+ mbus->bin_inited = mon_bin_add(mbus, ubus->busnum);
mutex_lock(&mon_lock);
list_add_tail(&mbus->bus_link, &mon_buses);
@@ -309,6 +316,18 @@ err_alloc:
return;
}
+static void mon_bus0_init(void)
+{
+ struct mon_bus *mbus = &mon_bus0;
+
+ kref_init(&mbus->ref);
+ spin_lock_init(&mbus->lock);
+ INIT_LIST_HEAD(&mbus->r_list);
+
+ mbus->text_inited = mon_text_add(mbus, 0);
+ mbus->bin_inited = mon_bin_add(mbus, 0);
+}
+
/*
* Search a USB bus by number. Notice that USB bus numbers start from one,
* which we may later use to identify "all" with zero.
@@ -322,6 +341,9 @@ struct mon_bus *mon_bus_lookup(unsigned
struct list_head *p;
struct mon_bus *mbus;
+ if (num == 0) {
+ return &mon_bus0;
+ }
list_for_each (p, &mon_buses) {
mbus = list_entry(p, struct mon_bus, bus_link);
if (mbus->u_bus->busnum == num) {
@@ -341,6 +363,8 @@ static int __init mon_init(void)
if ((rc = mon_bin_init()) != 0)
goto err_bin;
+ mon_bus0_init();
+
if (usb_mon_register(&mon_ops_0) != 0) {
printk(KERN_NOTICE TAG ": unable to register with the core\n");
rc = -ENODEV;
@@ -374,6 +398,7 @@ static void __exit mon_exit(void)
usb_mon_deregister();
mutex_lock(&mon_lock);
+
while (!list_empty(&mon_buses)) {
p = mon_buses.next;
mbus = list_entry(p, struct mon_bus, bus_link);
@@ -381,6 +406,8 @@ static void __exit mon_exit(void)
if (mbus->text_inited)
mon_text_del(mbus);
+ if (mbus->bin_inited)
+ mon_bin_del(mbus);
/*
* This never happens, because the open/close paths in
@@ -397,6 +424,13 @@ static void __exit mon_exit(void)
mon_dissolve(mbus, mbus->u_bus);
kref_put(&mbus->ref, mon_bus_drop);
}
+
+ mbus = &mon_bus0;
+ if (mbus->text_inited)
+ mon_text_del(mbus);
+ if (mbus->bin_inited)
+ mon_bin_del(mbus);
+
mutex_unlock(&mon_lock);
mon_text_exit();
diff -urp -X dontdiff linux-2.6.21-rc6-git2-gregkh/drivers/usb/mon/mon_text.c
linux-2.6.21-mon/drivers/usb/mon/mon_text.c
--- linux-2.6.21-rc6-git2-gregkh/drivers/usb/mon/mon_text.c 2007-04-10
23:34:27.000000000 -0700
+++ linux-2.6.21-mon/drivers/usb/mon/mon_text.c 2007-03-05 14:18:00.000000000
-0800
@@ -124,8 +124,10 @@ static inline char mon_text_get_setup(st
if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
return '-';
- if (mbus->uses_dma && (urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ if (urb->dev->bus->uses_dma &&
+ (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
+ }
if (urb->setup_packet == NULL)
return 'Z'; /* '0' would be not as pretty. */
@@ -160,8 +162,10 @@ static inline char mon_text_get_data(str
* contain non-NULL garbage in case the upper level promised to
* set DMA for the HCD.
*/
- if (mbus->uses_dma && (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ if (urb->dev->bus->uses_dma &&
+ (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
return mon_dmapeek(ep->data, urb->transfer_dma, len);
+ }
if (urb->transfer_buffer == NULL)
return 'Z'; /* '0' would be not as pretty. */
@@ -201,7 +205,7 @@ static void mon_text_event(struct mon_re
ep->type = ev_type;
ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
- ep->busnum = rp->r.m_bus->u_bus->busnum;
+ ep->busnum = urb->dev->bus->busnum;
ep->tstamp = stamp;
ep->length = (ev_type == 'S') ?
urb->transfer_buffer_length : urb->actual_length;
@@ -305,13 +309,11 @@ static struct mon_event_text *mon_text_f
static int mon_text_open(struct inode *inode, struct file *file)
{
struct mon_bus *mbus;
- struct usb_bus *ubus;
struct mon_reader_text *rp;
int rc;
mutex_lock(&mon_lock);
mbus = inode->i_private;
- ubus = mbus->u_bus;
rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
if (rp == NULL) {
@@ -335,8 +337,7 @@ static int mon_text_open(struct inode *i
rp->r.rnf_error = mon_text_error;
rp->r.rnf_complete = mon_text_complete;
- snprintf(rp->slab_name, SLAB_NAME_SZ, "mon%dt_%lx", ubus->busnum,
- (long)rp);
+ snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
rp->e_slab = kmem_cache_create(rp->slab_name,
sizeof(struct mon_event_text), sizeof(long), 0,
mon_text_ctor, NULL);
@@ -654,14 +655,14 @@ static const struct file_operations mon_
.release = mon_text_release,
};
-int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+int mon_text_add(struct mon_bus *mbus, int busnum)
{
struct dentry *d;
enum { NAMESZ = 10 };
char name[NAMESZ];
int rc;
- rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+ rc = snprintf(name, NAMESZ, "%dt", busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_t;
d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_t);
@@ -669,7 +670,7 @@ int mon_text_add(struct mon_bus *mbus, c
goto err_create_t;
mbus->dent_t = d;
- rc = snprintf(name, NAMESZ, "%du", ubus->busnum);
+ rc = snprintf(name, NAMESZ, "%du", busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_u;
d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_u);
@@ -677,7 +678,7 @@ int mon_text_add(struct mon_bus *mbus, c
goto err_create_u;
mbus->dent_u = d;
- rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+ rc = snprintf(name, NAMESZ, "%ds", busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_s;
d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
diff -urp -X dontdiff linux-2.6.21-rc6-git2-gregkh/drivers/usb/mon/usb_mon.h
linux-2.6.21-mon/drivers/usb/mon/usb_mon.h
--- linux-2.6.21-rc6-git2-gregkh/drivers/usb/mon/usb_mon.h 2007-04-10
23:34:27.000000000 -0700
+++ linux-2.6.21-mon/drivers/usb/mon/usb_mon.h 2007-03-05 14:59:35.000000000
-0800
@@ -20,10 +20,11 @@ struct mon_bus {
struct usb_bus *u_bus;
int text_inited;
+ int bin_inited;
struct dentry *dent_s; /* Debugging file */
struct dentry *dent_t; /* Text interface file */
struct dentry *dent_u; /* Second text interface file */
- int uses_dma;
+ struct device *classdev; /* Device in usbmon class */
/* Ref */
int nreaders; /* Under mon_lock AND mbus->lock */
@@ -53,9 +54,10 @@ void mon_reader_del(struct mon_bus *mbus
struct mon_bus *mon_bus_lookup(unsigned int num);
-int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+int /*bool*/ mon_text_add(struct mon_bus *mbus, int busnum);
void mon_text_del(struct mon_bus *mbus);
-// void mon_bin_add(struct mon_bus *);
+int /*bool*/ mon_bin_add(struct mon_bus *mbus, int busnum);
+void mon_bin_del(struct mon_bus *mbus);
int __init mon_text_init(void);
void mon_text_exit(void);
@@ -82,4 +84,6 @@ extern struct mutex mon_lock;
extern const struct file_operations mon_fops_stat;
+extern struct mon_bus mon_bus0; /* Only for redundant checks */
+
#endif /* __USB_MON_H */
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel