diff options
Diffstat (limited to 'drivers/usb/mon/mon_text.c')
| -rw-r--r-- | drivers/usb/mon/mon_text.c | 126 | 
1 files changed, 78 insertions, 48 deletions
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index f5e1bb5e5217..984f7e12a6a5 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -85,6 +85,8 @@ struct mon_reader_text {  	wait_queue_head_t wait;  	int printf_size; +	size_t printf_offset; +	size_t printf_togo;  	char *printf_buf;  	struct mutex printf_lock; @@ -376,75 +378,103 @@ err_alloc:  	return rc;  } -/* - * For simplicity, we read one record in one system call and throw out - * what does not fit. This means that the following does not work: - *   dd if=/dbg/usbmon/0t bs=10 - * Also, we do not allow seeks and do not bother advancing the offset. - */ +static ssize_t mon_text_copy_to_user(struct mon_reader_text *rp, +    char __user * const buf, const size_t nbytes) +{ +	const size_t togo = min(nbytes, rp->printf_togo); + +	if (copy_to_user(buf, &rp->printf_buf[rp->printf_offset], togo)) +		return -EFAULT; +	rp->printf_togo -= togo; +	rp->printf_offset += togo; +	return togo; +} + +/* ppos is not advanced since the llseek operation is not permitted. */  static ssize_t mon_text_read_t(struct file *file, char __user *buf, -				size_t nbytes, loff_t *ppos) +    size_t nbytes, loff_t *ppos)  {  	struct mon_reader_text *rp = file->private_data;  	struct mon_event_text *ep;  	struct mon_text_ptr ptr; +	ssize_t ret; -	ep = mon_text_read_wait(rp, file); -	if (IS_ERR(ep)) -		return PTR_ERR(ep);  	mutex_lock(&rp->printf_lock); -	ptr.cnt = 0; -	ptr.pbuf = rp->printf_buf; -	ptr.limit = rp->printf_size; - -	mon_text_read_head_t(rp, &ptr, ep); -	mon_text_read_statset(rp, &ptr, ep); -	ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, -	    " %d", ep->length); -	mon_text_read_data(rp, &ptr, ep); - -	if (copy_to_user(buf, rp->printf_buf, ptr.cnt)) -		ptr.cnt = -EFAULT; + +	if (rp->printf_togo == 0) { + +		ep = mon_text_read_wait(rp, file); +		if (IS_ERR(ep)) { +			mutex_unlock(&rp->printf_lock); +			return PTR_ERR(ep); +		} +		ptr.cnt = 0; +		ptr.pbuf = rp->printf_buf; +		ptr.limit = rp->printf_size; + +		mon_text_read_head_t(rp, &ptr, ep); +		mon_text_read_statset(rp, &ptr, ep); +		ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, +		    " %d", ep->length); +		mon_text_read_data(rp, &ptr, ep); + +		rp->printf_togo = ptr.cnt; +		rp->printf_offset = 0; + +		kmem_cache_free(rp->e_slab, ep); +	} + +	ret = mon_text_copy_to_user(rp, buf, nbytes);  	mutex_unlock(&rp->printf_lock); -	kmem_cache_free(rp->e_slab, ep); -	return ptr.cnt; +	return ret;  } +/* ppos is not advanced since the llseek operation is not permitted. */  static ssize_t mon_text_read_u(struct file *file, char __user *buf, -				size_t nbytes, loff_t *ppos) +    size_t nbytes, loff_t *ppos)  {  	struct mon_reader_text *rp = file->private_data;  	struct mon_event_text *ep;  	struct mon_text_ptr ptr; +	ssize_t ret; -	ep = mon_text_read_wait(rp, file); -	if (IS_ERR(ep)) -		return PTR_ERR(ep);  	mutex_lock(&rp->printf_lock); -	ptr.cnt = 0; -	ptr.pbuf = rp->printf_buf; -	ptr.limit = rp->printf_size; -	mon_text_read_head_u(rp, &ptr, ep); -	if (ep->type == 'E') { -		mon_text_read_statset(rp, &ptr, ep); -	} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { -		mon_text_read_isostat(rp, &ptr, ep); -		mon_text_read_isodesc(rp, &ptr, ep); -	} else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { -		mon_text_read_intstat(rp, &ptr, ep); -	} else { -		mon_text_read_statset(rp, &ptr, ep); +	if (rp->printf_togo == 0) { + +		ep = mon_text_read_wait(rp, file); +		if (IS_ERR(ep)) { +			mutex_unlock(&rp->printf_lock); +			return PTR_ERR(ep); +		} +		ptr.cnt = 0; +		ptr.pbuf = rp->printf_buf; +		ptr.limit = rp->printf_size; + +		mon_text_read_head_u(rp, &ptr, ep); +		if (ep->type == 'E') { +			mon_text_read_statset(rp, &ptr, ep); +		} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { +			mon_text_read_isostat(rp, &ptr, ep); +			mon_text_read_isodesc(rp, &ptr, ep); +		} else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { +			mon_text_read_intstat(rp, &ptr, ep); +		} else { +			mon_text_read_statset(rp, &ptr, ep); +		} +		ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, +		    " %d", ep->length); +		mon_text_read_data(rp, &ptr, ep); + +		rp->printf_togo = ptr.cnt; +		rp->printf_offset = 0; + +		kmem_cache_free(rp->e_slab, ep);  	} -	ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, -	    " %d", ep->length); -	mon_text_read_data(rp, &ptr, ep); -	if (copy_to_user(buf, rp->printf_buf, ptr.cnt)) -		ptr.cnt = -EFAULT; +	ret = mon_text_copy_to_user(rp, buf, nbytes);  	mutex_unlock(&rp->printf_lock); -	kmem_cache_free(rp->e_slab, ep); -	return ptr.cnt; +	return ret;  }  static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,  |