diff options
Diffstat (limited to 'drivers/usb/mon/mon_bin.c')
| -rw-r--r-- | drivers/usb/mon/mon_bin.c | 142 | 
1 files changed, 116 insertions, 26 deletions
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 4cf27c72423..f8d9045d668 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -37,10 +37,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  /* @@ -92,7 +95,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 */ @@ -102,7 +127,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) */  }; @@ -131,6 +156,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 @@ -360,12 +390,8 @@ static inline char mon_bin_get_setup(unsigned char *setupb,      const struct urb *urb, char ev_type)  { -	if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S') -		return '-'; -  	if (urb->setup_packet == NULL)  		return 'Z'; -  	memcpy(setupb, urb->setup_packet, SETUP_LEN);  	return 0;  } @@ -387,6 +413,26 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,  	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, int status)  { @@ -396,6 +442,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,  	unsigned int urb_length;  	unsigned int offset;  	unsigned int length; +	unsigned int ndesc, lendesc;  	unsigned char dir;  	struct mon_bin_hdr *ep;  	char data_tag = 0; @@ -407,6 +454,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,  	/*  	 * Find the maximum allowable length, then allocate space.  	 */ +	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; +		} +	} 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; @@ -429,10 +489,12 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,  		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); @@ -456,9 +518,31 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,  	ep->ts_usec = ts.tv_usec;  	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' */ @@ -592,7 +676,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; @@ -609,7 +694,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;  	} @@ -657,6 +742,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; @@ -674,8 +760,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); @@ -687,13 +773,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)) { +	if (rp->b_read >= hdrbytes) {  		step_len = ep->len_cap; -		step_len -= rp->b_read - sizeof(struct mon_bin_hdr); +		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)) { @@ -709,7 +795,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); @@ -908,6 +994,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; @@ -917,8 +1004,9 @@ 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); +		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; @@ -984,16 +1072,18 @@ static long mon_bin_compat_ioctl(struct file *file,  	switch (cmd) { -	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);  		if (ret < 0)  			return ret;  		}  |