diff options
Diffstat (limited to 'drivers/usb/mon/mon_text.c')
| -rw-r--r-- | drivers/usb/mon/mon_text.c | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 9f1a9227ebe..ad408251d95 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -7,9 +7,12 @@ #include <linux/kernel.h> #include <linux/list.h> #include <linux/usb.h> +#include <linux/slab.h> #include <linux/time.h> +#include <linux/export.h> #include <linux/mutex.h> #include <linux/debugfs.h> +#include <linux/scatterlist.h> #include <asm/uaccess.h> #include "usb_mon.h" @@ -137,6 +140,8 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, int len, char ev_type, struct mon_bus *mbus) { + void *src; + if (len <= 0) return 'L'; if (len >= DATA_MAX) @@ -150,10 +155,22 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, return '>'; } - if (urb->transfer_buffer == NULL) - return 'Z'; /* '0' would be not as pretty. */ + if (urb->num_sgs == 0) { + src = urb->transfer_buffer; + if (src == NULL) + return 'Z'; /* '0' would be not as pretty. */ + } else { + struct scatterlist *sg = urb->sg; + + if (PageHighMem(sg_page(sg))) + return 'D'; + + /* For the text interface we copy only the first sg buffer */ + len = min_t(int, sg->length, len); + src = sg_virt(sg); + } - memcpy(ep->data, urb->transfer_buffer, len); + memcpy(ep->data, src, len); return 0; } @@ -163,7 +180,7 @@ static inline unsigned int mon_get_timestamp(void) unsigned int stamp; do_gettimeofday(&tval); - stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s. */ + stamp = tval.tv_sec & 0xFFF; /* 2^32 = 4294967296. Limit to 4096s. */ stamp = stamp * 1000000 + tval.tv_usec; return stamp; } @@ -220,6 +237,9 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, fp++; dp++; } + /* Wasteful, but simple to understand: ISO 'C' is sparse. */ + if (ev_type == 'C') + ep->length = urb->transfer_buffer_length; } ep->setup_flag = mon_text_get_setup(ep, urb, ev_type, rp->r.m_bus); @@ -256,12 +276,12 @@ static void mon_text_error(void *data, struct urb *urb, int error) ep->type = 'E'; ep->id = (unsigned long) urb; - ep->busnum = 0; + ep->busnum = urb->dev->bus->busnum; ep->devnum = urb->dev->devnum; ep->epnum = usb_endpoint_num(&urb->ep->desc); ep->xfertype = usb_endpoint_type(&urb->ep->desc); ep->is_in = usb_urb_dir_in(urb); - ep->tstamp = 0; + ep->tstamp = mon_get_timestamp(); ep->length = 0; ep->status = error; @@ -651,6 +671,9 @@ int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus) int busnum = ubus? ubus->busnum: 0; int rc; + if (mon_dir == NULL) + return 0; + if (ubus != NULL) { rc = snprintf(name, NAMESZ, "%dt", busnum); if (rc <= 0 || rc >= NAMESZ) @@ -721,12 +744,12 @@ int __init mon_text_init(void) mondir = debugfs_create_dir("usbmon", usb_debug_root); if (IS_ERR(mondir)) { - printk(KERN_NOTICE TAG ": debugfs is not available\n"); - return -ENODEV; + /* debugfs not available, but we can use usbmon without it */ + return 0; } if (mondir == NULL) { printk(KERN_NOTICE TAG ": unable to create usbmon directory\n"); - return -ENODEV; + return -ENOMEM; } mon_dir = mondir; return 0; |
