diff options
Diffstat (limited to 'drivers/usb/mon')
| -rw-r--r-- | drivers/usb/mon/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/usb/mon/Makefile | 7 | ||||
| -rw-r--r-- | drivers/usb/mon/mon_bin.c | 421 | ||||
| -rw-r--r-- | drivers/usb/mon/mon_dma.c | 95 | ||||
| -rw-r--r-- | drivers/usb/mon/mon_main.c | 33 | ||||
| -rw-r--r-- | drivers/usb/mon/mon_stat.c | 21 | ||||
| -rw-r--r-- | drivers/usb/mon/mon_text.c | 129 | ||||
| -rw-r--r-- | drivers/usb/mon/usb_mon.h | 16 |
8 files changed, 398 insertions, 334 deletions
diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig index deb9ddffa40..5c6ffa2a612 100644 --- a/drivers/usb/mon/Kconfig +++ b/drivers/usb/mon/Kconfig @@ -3,14 +3,10 @@ # config USB_MON - bool "USB Monitor" - depends on USB!=n - default y + tristate "USB Monitor" help - If you say Y here, a component which captures the USB traffic + If you select this option, a component which captures the USB traffic between peripheral-specific drivers and HC drivers will be built. For more information, see <file:Documentation/usb/usbmon.txt>. - This is somewhat experimental at this time, but it should be safe. - - If unsure, say Y. + If unsure, say Y, if allowed, otherwise M. diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile index 90c59535778..8ed24ab0869 100644 --- a/drivers/usb/mon/Makefile +++ b/drivers/usb/mon/Makefile @@ -1,8 +1,7 @@ # -# Makefile for USB Core files and filesystem +# Makefile for USB monitor # -usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o +usbmon-y := mon_main.o mon_stat.o mon_text.o mon_bin.o -# This does not use CONFIG_USB_MON because we want this to use a tristate. -obj-$(CONFIG_USB) += usbmon.o +obj-$(CONFIG_USB_MON) += usbmon.o diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index c03dfd7a9d3..9a62e89d6dc 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -11,10 +11,13 @@ #include <linux/types.h> #include <linux/fs.h> #include <linux/cdev.h> +#include <linux/export.h> #include <linux/usb.h> #include <linux/poll.h> #include <linux/compat.h> #include <linux/mm.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> #include <asm/uaccess.h> @@ -36,9 +39,13 @@ #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 +97,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 +129,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 +158,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 +206,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp, #define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0) +static unsigned char xfer_to_pipe[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +}; + static struct class *mon_bin_class; static dev_t mon_bin_dev0; static struct cdev mon_bin_cdev; @@ -184,9 +222,8 @@ static void mon_free_buff(struct mon_pgmap *map, int npages); /* * This is a "chunked memcpy". It does not manipulate any counters. - * But it returns the new offset for repeated application. */ -unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, +static unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, unsigned int off, const unsigned char *from, unsigned int length) { unsigned int step_len; @@ -314,12 +351,12 @@ static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp, /* * Return a few (kilo-)bytes to the head of the buffer. - * This is used if a DMA fetch fails. + * This is used if a data fetch fails. */ static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size) { - size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + /* size &= ~(PKT_ALIGN-1); -- we're called with aligned size */ rp->b_cnt -= size; if (rp->b_in < size) rp->b_in += rp->b_size; @@ -354,45 +391,106 @@ static inline char mon_bin_get_setup(unsigned char *setupb, const struct urb *urb, char ev_type) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') - return '-'; - - 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'; - memcpy(setupb, urb->setup_packet, SETUP_LEN); return 0; } -static char mon_bin_get_data(const struct mon_reader_bin *rp, - unsigned int offset, struct urb *urb, unsigned int length) +static unsigned int mon_bin_get_data(const struct mon_reader_bin *rp, + unsigned int offset, struct urb *urb, unsigned int length, + char *flag) { + int i; + struct scatterlist *sg; + unsigned int this_len; + + *flag = 0; + if (urb->num_sgs == 0) { + if (urb->transfer_buffer == NULL) { + *flag = 'Z'; + return length; + } + mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); + length = 0; - 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; + } else { + /* If IOMMU coalescing occurred, we cannot trust sg_page */ + if (urb->transfer_flags & URB_DMA_SG_COMBINED) { + *flag = 'D'; + return length; + } + + /* Copy up to the first non-addressable segment */ + for_each_sg(urb->sg, sg, urb->num_sgs, i) { + if (length == 0 || PageHighMem(sg_page(sg))) + break; + this_len = min_t(unsigned int, sg->length, length); + offset = mon_copy_to_buff(rp, offset, sg_virt(sg), + this_len); + length -= this_len; + } + if (i == 0) + *flag = 'D'; } - if (urb->transfer_buffer == NULL) - return 'Z'; + return length; +} - mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); - return 0; +/* + * This is the look-ahead pass in case of 'C Zi', when actual_length cannot + * be used to determine the length of the whole contiguous buffer. + */ +static unsigned int mon_bin_collate_isodesc(const struct mon_reader_bin *rp, + struct urb *urb, unsigned int ndesc) +{ + struct usb_iso_packet_descriptor *fp; + unsigned int length; + + length = 0; + fp = urb->iso_frame_desc; + while (ndesc-- != 0) { + if (fp->actual_length != 0) { + if (fp->offset + fp->actual_length > length) + length = fp->offset + fp->actual_length; + } + fp++; + } + return length; +} + +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) + char ev_type, int status) { - unsigned long flags; + const struct usb_endpoint_descriptor *epd = &urb->ep->desc; struct timeval ts; + unsigned long flags; unsigned int urb_length; unsigned int offset; unsigned int length; + unsigned int delta; + unsigned int ndesc, lendesc; + unsigned char dir; struct mon_bin_hdr *ep; char data_tag = 0; @@ -407,25 +505,49 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, urb->transfer_buffer_length : urb->actual_length; length = urb_length; + if (usb_endpoint_xfer_isoc(epd)) { + 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; + } + if (ev_type == 'C' && usb_urb_dir_in(urb)) + length = mon_bin_collate_isodesc(rp, urb, ndesc); + } else { + ndesc = 0; + } + lendesc = ndesc*sizeof(struct mon_bin_isodesc); + + /* not an issue unless there's a subtle bug in a HCD somewhere */ + if (length >= urb->transfer_buffer_length) + length = urb->transfer_buffer_length; + if (length >= rp->b_size/5) length = rp->b_size/5; - if (usb_pipein(urb->pipe)) { + if (usb_urb_dir_in(urb)) { if (ev_type == 'S') { length = 0; data_tag = '<'; } + /* Cannot rely on endpoint number in case of control ep.0 */ + dir = USB_DIR_IN; } else { if (ev_type == 'C') { length = 0; data_tag = '>'; } + dir = 0; } - 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,24 +562,48 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, */ memset(ep, 0, PKT_SIZE); ep->type = ev_type; - ep->xfer_type = usb_pipetype(urb->pipe); - /* 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->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)]; + ep->epnum = dir | usb_endpoint_num(epd); + ep->devnum = urb->dev->devnum; 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->status = status; ep->len_urb = urb_length; - ep->len_cap = length; + ep->len_cap = length + lendesc; + ep->xfer_flags = urb->transfer_flags; + + if (usb_endpoint_xfer_int(epd)) { + ep->interval = urb->interval; + } else if (usb_endpoint_xfer_isoc(epd)) { + 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_endpoint_xfer_control(epd) && 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' */ - ep->len_cap = 0; - mon_buff_area_shrink(rp, length); + length = mon_bin_get_data(rp, offset, urb, length, + &ep->flag_data); + if (length > 0) { + delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + ep->len_cap -= length; + delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + mon_buff_area_shrink(rp, delta); } } else { ep->flag_data = data_tag; @@ -471,22 +617,25 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, static void mon_bin_submit(void *data, struct urb *urb) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'S'); + mon_bin_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_bin_complete(void *data, struct urb *urb) +static void mon_bin_complete(void *data, struct urb *urb, int status) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'C'); + mon_bin_event(rp, urb, 'C', status); } static void mon_bin_error(void *data, struct urb *urb, int error) { struct mon_reader_bin *rp = data; + struct timeval ts; unsigned long flags; unsigned int offset; struct mon_bin_hdr *ep; + do_gettimeofday(&ts); + spin_lock_irqsave(&rp->b_lock, flags); offset = mon_buff_area_alloc(rp, PKT_SIZE); @@ -500,12 +649,14 @@ static void mon_bin_error(void *data, struct urb *urb, int error) memset(ep, 0, PKT_SIZE); ep->type = 'E'; - ep->xfer_type = usb_pipetype(urb->pipe); - /* 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->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)]; + ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0; + ep->epnum |= usb_endpoint_num(&urb->ep->desc); + ep->devnum = urb->dev->devnum; 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 = error; ep->flag_setup = '-'; @@ -542,7 +693,6 @@ static int mon_bin_open(struct inode *inode, struct file *file) 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); @@ -581,7 +731,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; @@ -598,7 +749,7 @@ static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp, 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; } @@ -646,6 +797,7 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf, 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; @@ -663,8 +815,8 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf, 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); @@ -676,10 +828,13 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf, done += step_len; } - if (rp->b_read >= sizeof(struct mon_bin_hdr)) { - step_len = min(nbytes, (size_t)ep->len_cap); + if (rp->b_read >= hdrbytes) { + step_len = ep->len_cap; + step_len -= rp->b_read - hdrbytes; + if (step_len > nbytes) + step_len = nbytes; 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)) { @@ -695,7 +850,7 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf, /* * 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); @@ -822,8 +977,7 @@ static int mon_bin_queued(struct mon_reader_bin *rp) /* */ -static int mon_bin_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct mon_reader_bin *rp = file->private_data; // struct mon_bus* mbus = rp->r.m_bus; @@ -878,7 +1032,7 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file, mutex_lock(&rp->fetch_lock); spin_lock_irqsave(&rp->b_lock, flags); - mon_free_buff(rp->b_vec, size/CHUNK_SIZE); + mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE); kfree(rp->b_vec); rp->b_vec = vec; rp->b_size = size; @@ -894,6 +1048,7 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file, break; case MON_IOCX_GET: + case MON_IOCX_GETX: { struct mon_bin_get getb; @@ -903,25 +1058,11 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file, 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); - } - break; - -#ifdef CONFIG_COMPAT - case MON_IOCX_GET32: { - 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, getb.hdr, + (cmd == MON_IOCX_GET)? PKT_SZ_API0: PKT_SZ_API1, + getb.data, (unsigned int)getb.alloc); } break; -#endif case MON_IOCX_MFETCH: { @@ -949,7 +1090,59 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file, } break; + case MON_IOCG_STATS: { + struct mon_bin_stats __user *sp; + unsigned int nevents; + unsigned int ndropped; + + spin_lock_irqsave(&rp->b_lock, flags); + ndropped = rp->cnt_lost; + rp->cnt_lost = 0; + spin_unlock_irqrestore(&rp->b_lock, flags); + nevents = mon_bin_queued(rp); + + sp = (struct mon_bin_stats __user *)arg; + if (put_user(ndropped, &sp->dropped)) + return -EFAULT; + if (put_user(nevents, &sp->queued)) + return -EFAULT; + + } + break; + + default: + return -ENOTTY; + } + + return ret; +} + #ifdef CONFIG_COMPAT +static long mon_bin_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mon_reader_bin *rp = file->private_data; + int ret; + + switch (cmd) { + + 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), + (cmd == MON_IOCX_GET32)? PKT_SZ_API0: PKT_SZ_API1, + compat_ptr(getb.data32), getb.alloc32); + if (ret < 0) + return ret; + } + return 0; + case MON_IOCX_MFETCH32: { struct mon_bin_mfetch32 mfetch; @@ -973,37 +1166,24 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file, return ret; if (put_user(ret, &uptr->nfetch32)) return -EFAULT; - ret = 0; } - break; -#endif - - case MON_IOCG_STATS: { - struct mon_bin_stats __user *sp; - unsigned int nevents; - unsigned int ndropped; - - spin_lock_irqsave(&rp->b_lock, flags); - ndropped = rp->cnt_lost; - rp->cnt_lost = 0; - spin_unlock_irqrestore(&rp->b_lock, flags); - nevents = mon_bin_queued(rp); + return 0; - sp = (struct mon_bin_stats __user *)arg; - if (put_user(rp->cnt_lost, &sp->dropped)) - return -EFAULT; - if (put_user(nevents, &sp->queued)) - return -EFAULT; + case MON_IOCG_STATS: + return mon_bin_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); - } - break; + case MON_IOCQ_URB_LEN: + case MON_IOCQ_RING_SIZE: + case MON_IOCT_RING_SIZE: + case MON_IOCH_MFLUSH: + return mon_bin_ioctl(file, cmd, arg); default: - return -ENOTTY; + ; } - - return ret; + return -ENOTTY; } +#endif /* CONFIG_COMPAT */ static unsigned int mon_bin_poll(struct file *file, struct poll_table_struct *wait) @@ -1041,49 +1221,51 @@ static void mon_bin_vma_close(struct vm_area_struct *vma) /* * Map ring pages to user space. */ -struct page *mon_bin_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct mon_reader_bin *rp = vma->vm_private_data; unsigned long offset, chunk_idx; struct page *pageptr; - offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + offset = vmf->pgoff << PAGE_SHIFT; if (offset >= rp->b_size) - return NOPAGE_SIGBUS; + return VM_FAULT_SIGBUS; chunk_idx = offset / CHUNK_SIZE; pageptr = rp->b_vec[chunk_idx].pg; get_page(pageptr); - if (type) - *type = VM_FAULT_MINOR; - return pageptr; + vmf->page = pageptr; + return 0; } -struct vm_operations_struct mon_bin_vm_ops = { +static const struct vm_operations_struct mon_bin_vm_ops = { .open = mon_bin_vma_open, .close = mon_bin_vma_close, - .nopage = mon_bin_vma_nopage, + .fault = mon_bin_vma_fault, }; -int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) +static int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) { - /* don't do anything here: "nopage" will set up page table entries */ + /* don't do anything here: "fault" will set up page table entries */ vma->vm_ops = &mon_bin_vm_ops; - vma->vm_flags |= VM_RESERVED; + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; vma->vm_private_data = filp->private_data; mon_bin_vma_open(vma); return 0; } -struct file_operations mon_fops_binary = { +static const struct file_operations mon_fops_binary = { .owner = THIS_MODULE, .open = mon_bin_open, .llseek = no_llseek, .read = mon_bin_read, /* .write = mon_text_write, */ .poll = mon_bin_poll, - .ioctl = mon_bin_ioctl, + .unlocked_ioctl = mon_bin_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = mon_bin_compat_ioctl, +#endif .release = mon_bin_release, + .mmap = mon_bin_mmap, }; static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp) @@ -1132,7 +1314,7 @@ static int mon_alloc_buff(struct mon_pgmap *map, int npages) return -ENOMEM; } map[n].ptr = (unsigned char *) vaddr; - map[n].pg = virt_to_page(vaddr); + map[n].pg = virt_to_page((void *) vaddr); } return 0; } @@ -1153,8 +1335,9 @@ int mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus) if (minor >= MON_BIN_MAX_MINOR) return 0; - dev = device_create(mon_bin_class, ubus? ubus->controller: NULL, - MKDEV(MAJOR(mon_bin_dev0), minor), "usbmon%d", minor); + dev = device_create(mon_bin_class, ubus ? ubus->controller : NULL, + MKDEV(MAJOR(mon_bin_dev0), minor), NULL, + "usbmon%d", minor); if (IS_ERR(dev)) return 0; diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c deleted file mode 100644 index 140cc80bd2b..00000000000 --- a/drivers/usb/mon/mon_dma.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * The USB Monitor, inspired by Dave Harding's USBMon. - * - * mon_dma.c: Library which snoops on DMA areas. - * - * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com) - */ -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/highmem.h> -#include <asm/page.h> - -#include <linux/usb.h> /* Only needed for declarations in usb_mon.h */ -#include "usb_mon.h" - -/* - * 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) - -char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len) -{ - struct page *pg; - unsigned long flags; - unsigned char *map; - unsigned char *ptr; - - /* - * 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); - - /* - * 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); - map = kmap_atomic(pg, KM_IRQ0); - ptr = map + (dma_addr & (PAGE_SIZE-1)); - memcpy(dst, ptr, len); - kunmap_atomic(map, KM_IRQ0); - local_irq_restore(flags); - return 0; -} - -void mon_dmapeek_vec(const struct mon_reader_bin *rp, - unsigned int offset, dma_addr_t dma_addr, unsigned int length) -{ - unsigned long flags; - unsigned int step_len; - struct page *pg; - unsigned char *map; - unsigned long page_off, page_len; - - local_irq_save(flags); - while (length) { - /* compute number of bytes we are going to copy in this page */ - step_len = length; - page_off = dma_addr & (PAGE_SIZE-1); - page_len = PAGE_SIZE - page_off; - if (page_len < step_len) - step_len = page_len; - - /* copy data and advance pointers */ - pg = phys_to_page(dma_addr); - map = kmap_atomic(pg, KM_IRQ0); - offset = mon_copy_to_buff(rp, offset, map + page_off, step_len); - kunmap_atomic(map, KM_IRQ0); - dma_addr += step_len; - length -= step_len; - } - local_irq_restore(flags); -} - -#endif /* __i386__ */ - -#ifndef MON_HAS_UNMAP -char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len) -{ - return 'D'; -} - -void mon_dmapeek_vec(const struct mon_reader_bin *rp, - unsigned int offset, dma_addr_t dma_addr, unsigned int length) -{ - ; -} - -#endif /* MON_HAS_UNMAP */ diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index ce61d8b0fd8..10405119985 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -9,11 +9,13 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/slab.h> #include <linux/notifier.h> #include <linux/mutex.h> #include "usb_mon.h" -#include "../core/hcd.h" + static void mon_stop(struct mon_bus *mbus); static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus); @@ -88,7 +90,6 @@ static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb) r->rnf_submit(r->r_data, urb); } spin_unlock_irqrestore(&mbus->lock, flags); - return; } static void mon_submit(struct usb_bus *ubus, struct urb *urb) @@ -115,7 +116,6 @@ static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int erro r->rnf_error(r->r_data, urb, error); } spin_unlock_irqrestore(&mbus->lock, flags); - return; } static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) @@ -129,7 +129,7 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) /* */ -static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) +static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, int status) { unsigned long flags; struct list_head *pos; @@ -139,28 +139,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) 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); + r->rnf_complete(r->r_data, urb, status); } spin_unlock_irqrestore(&mbus->lock, flags); } -static void mon_complete(struct usb_bus *ubus, struct urb *urb) +static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status) { struct mon_bus *mbus; - mbus = ubus->mon_bus; - if (mbus == NULL) { - /* - * This should not happen. - * At this point we do not even know the bus number... - */ - printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n", - urb->pipe); - return; - } - - mon_bus_complete(mbus, urb); - mon_bus_complete(&mon_bus0, urb); + if ((mbus = ubus->mon_bus) != NULL) + mon_bus_complete(mbus, urb, status); + mon_bus_complete(&mon_bus0, urb, status); } /* int (*unlink_urb) (struct urb *urb, int status); */ @@ -170,7 +160,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) */ static void mon_stop(struct mon_bus *mbus) { - struct usb_bus *ubus = mbus->u_bus; + struct usb_bus *ubus; struct list_head *p; if (mbus == &mon_bus0) { @@ -371,12 +361,11 @@ static int __init mon_init(void) } // MOD_INC_USE_COUNT(which_module?); - usb_register_notify(&mon_nb); - mutex_lock(&usb_bus_list_lock); list_for_each_entry (ubus, &usb_bus_list, bus_list) { mon_bus_init(ubus); } + usb_register_notify(&mon_nb); mutex_unlock(&usb_bus_list_lock); return 0; diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c index f6d1491256c..ebd6189a501 100644 --- a/drivers/usb/mon/mon_stat.c +++ b/drivers/usb/mon/mon_stat.c @@ -8,7 +8,10 @@ */ #include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/export.h> #include <linux/usb.h> +#include <linux/fs.h> #include <asm/uaccess.h> #include "usb_mon.h" @@ -42,23 +45,15 @@ static ssize_t mon_stat_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { struct snap *sp = file->private_data; - loff_t pos = *ppos; - int cnt; - if (pos < 0 || pos >= sp->slen) - return 0; - if (nbytes == 0) - return 0; - if ((cnt = sp->slen - pos) > nbytes) - cnt = nbytes; - if (copy_to_user(buf, sp->str + pos, cnt)) - return -EFAULT; - *ppos = pos + cnt; - return cnt; + return simple_read_from_buffer(buf, nbytes, ppos, sp->str, sp->slen); } static int mon_stat_release(struct inode *inode, struct file *file) { + struct snap *sp = file->private_data; + file->private_data = NULL; + kfree(sp); return 0; } @@ -69,6 +64,6 @@ const struct file_operations mon_fops_stat = { .read = mon_stat_read, /* .write = mon_stat_write, */ /* .poll = mon_stat_poll, */ - /* .ioctl = mon_stat_ioctl, */ + /* .unlocked_ioctl = mon_stat_ioctl, */ .release = mon_stat_release, }; diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 8f27a9e1c36..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" @@ -50,10 +53,13 @@ struct mon_iso_desc { struct mon_event_text { struct list_head e_link; int type; /* submit, complete, etc. */ - unsigned int pipe; /* Pipe */ unsigned long id; /* From pointer, most of the time */ unsigned int tstamp; int busnum; + char devnum; + char epnum; + char is_in; + char xfertype; int length; /* Depends on type: xfer length or act length */ int status; int interval; @@ -84,7 +90,7 @@ struct mon_reader_text { static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */ -static void mon_text_ctor(void *, struct kmem_cache *, unsigned long); +static void mon_text_ctor(void *); struct mon_text_ptr { int cnt, limit; @@ -121,13 +127,9 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, struct urb *urb, char ev_type, struct mon_bus *mbus) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') return '-'; - 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. */ @@ -138,14 +140,14 @@ 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) { - int pipe = urb->pipe; + void *src; if (len <= 0) return 'L'; if (len >= DATA_MAX) len = DATA_MAX; - if (usb_pipein(pipe)) { + if (ep->is_in) { if (ev_type != 'C') return '<'; } else { @@ -153,24 +155,22 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, return '>'; } - /* - * The check to see if it's safe to poke at data has an enormous - * number of corner cases, but it seems that the following is - * more or less safe. - * - * 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. - */ - 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->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 (urb->transfer_buffer == NULL) - return 'Z'; /* '0' would be not as pretty. */ + if (PageHighMem(sg_page(sg))) + return 'D'; - memcpy(ep->data, urb->transfer_buffer, len); + /* 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, src, len); return 0; } @@ -180,13 +180,13 @@ 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; } static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { struct mon_event_text *ep; unsigned int stamp; @@ -203,24 +203,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, } ep->type = ev_type; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; 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 = stamp; ep->length = (ev_type == 'S') ? urb->transfer_buffer_length : urb->actual_length; /* Collecting status makes debugging sense for submits, too */ - ep->status = urb->status; + ep->status = status; - if (usb_pipeint(urb->pipe)) { + if (ep->xfertype == USB_ENDPOINT_XFER_INT) { ep->interval = urb->interval; - } else if (usb_pipeisoc(urb->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { ep->interval = urb->interval; ep->start_frame = urb->start_frame; ep->error_count = urb->error_count; } ep->numdesc = urb->number_of_packets; - if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) { + if (ep->xfertype == USB_ENDPOINT_XFER_ISOC && + urb->number_of_packets > 0) { if ((ndesc = urb->number_of_packets) > ISODESC_MAX) ndesc = ISODESC_MAX; fp = urb->iso_frame_desc; @@ -233,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); @@ -247,13 +254,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, static void mon_text_submit(void *data, struct urb *urb) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'S'); + mon_text_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_text_complete(void *data, struct urb *urb) +static void mon_text_complete(void *data, struct urb *urb, int status) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'C'); + mon_text_event(rp, urb, 'C', status); } static void mon_text_error(void *data, struct urb *urb, int error) @@ -268,10 +275,13 @@ static void mon_text_error(void *data, struct urb *urb, int error) } ep->type = 'E'; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; - ep->busnum = 0; - ep->tstamp = 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 = mon_get_timestamp(); ep->length = 0; ep->status = error; @@ -413,10 +423,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf, mon_text_read_head_u(rp, &ptr, ep); if (ep->type == 'E') { mon_text_read_statset(rp, &ptr, ep); - } else if (usb_pipeisoc(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { mon_text_read_isostat(rp, &ptr, ep); mon_text_read_isodesc(rp, &ptr, ep); - } else if (usb_pipeint(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { mon_text_read_intstat(rp, &ptr, ep); } else { mon_text_read_statset(rp, &ptr, ep); @@ -468,18 +478,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, - utype, udir, - usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->devnum, ep->epnum); } static void mon_text_read_head_u(struct mon_reader_text *rp, @@ -487,18 +496,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%d:%03u:%u", ep->id, ep->tstamp, ep->type, - utype, udir, - ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->busnum, ep->devnum, ep->epnum); } static void mon_text_read_statset(struct mon_reader_text *rp, @@ -663,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) @@ -718,7 +729,7 @@ void mon_text_del(struct mon_bus *mbus) /* * Slab interface: constructor. */ -static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sflags) +static void mon_text_ctor(void *mem) { /* * Nothing to initialize. No, really! @@ -731,14 +742,14 @@ int __init mon_text_init(void) { struct dentry *mondir; - mondir = debugfs_create_dir("usbmon", NULL); + 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; diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index f68ad6d99ad..df9a4df342c 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -46,7 +46,7 @@ struct mon_reader { void (*rnf_submit)(void *data, struct urb *urb); void (*rnf_error)(void *data, struct urb *urb, int error); - void (*rnf_complete)(void *data, struct urb *urb); + void (*rnf_complete)(void *data, struct urb *urb, int status); }; void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r); @@ -65,20 +65,6 @@ int __init mon_bin_init(void); void mon_bin_exit(void); /* - * DMA interface. - * - * XXX The vectored side needs a serious re-thinking. Abstracting vectors, - * like in Paolo's original patch, produces a double pkmap. We need an idea. -*/ -extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len); - -struct mon_reader_bin; -extern void mon_dmapeek_vec(const struct mon_reader_bin *rp, - unsigned int offset, dma_addr_t dma_addr, unsigned int len); -extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp, - unsigned int offset, const unsigned char *from, unsigned int len); - -/* */ extern struct mutex mon_lock; |
