Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae0d6cce authored by Pete Zaitcev's avatar Pete Zaitcev Committed by Greg Kroah-Hartman
Browse files

[PATCH] USB: Patch to make usbmon to print control setup packets



Make usbmon to print Setup packets of Control transfers. This is useful
when debugging enumeration issues.

This is a change to the trace format which is not fully compatible.
A parser has to look at the data length word now. If that word is
a character like 's', read setup packet before proceeding with data.
I decided not to bump the API tag for this because not many such
parsers exist at this point.

Signed-off-by: default avatarPete Zaitcev <zaitcev@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent ead99eb0
Loading
Loading
Loading
Loading
+21 −8
Original line number Diff line number Diff line
@@ -101,6 +101,13 @@ Here is the list of words, from left to right:
  or 3 and 2 positions, correspondingly.
- URB Status. This field makes no sense for submissions, but is present
  to help scripts with parsing. In error case, it contains the error code.
  In case of a setup packet, it contains a Setup Tag. If scripts read a number
  in this field, the proceed to read Data Length. Otherwise, they read
  the setup packet before reading the Data Length.
- Setup packet, if present, consists of 5 words: one of each for bmRequestType,
  bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0.
  These words are safe to decode if Setup Tag was 's'. Otherwise, the setup
  packet was present, but not captured, and the fields contain filler.
- Data Length. This is the actual length in the URB.
- Data tag. The usbmon may not always capture data, even if length is nonzero.
  Only if tag is '=', the data words are present.
@@ -125,25 +132,31 @@ class ParsedLine {
			String data_str = st.nextToken();
			int len = data_str.length() / 2;
			int i;
			int b;	// byte is signed, apparently?! XXX
			for (i = 0; i < len; i++) {
				data[data_len] = Byte.parseByte(
				// data[data_len] = Byte.parseByte(
				//     data_str.substring(i*2, i*2 + 2),
				//     16);
				b = Integer.parseInt(
				     data_str.substring(i*2, i*2 + 2),
				     16);
				if (b >= 128)
					b *= -1;
				data[data_len] = (byte) b;
				data_len++;
			}
		}
	}
}

This format is obviously deficient. For example, the setup packet for control
transfers is not delivered. This will change in the future.
This format may be changed in the future.

Examples:

An input control transfer to get a port status:
An input control transfer to get a port status.

d74ff9a0 2640288196 S Ci:001:00 -115 4 <
d74ff9a0 2640288202 C Ci:001:00 0 4 = 01010100
d5ea89a0 3575914555 S Ci:001:00 s a3 00 0000 0003 0004 4 <
d5ea89a0 3575914560 C Ci:001:00 0 4 = 01050000

An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper
to a storage device at address 5:
+43 −5
Original line number Diff line number Diff line
@@ -18,12 +18,17 @@
 */
#define DATA_MAX  32

/*
 * Defined by USB 2.0 clause 9.3, table 9.2.
 */
#define SETUP_MAX  8

/*
 * This limit exists to prevent OOMs when the user process stops reading.
 */
#define EVENT_MAX  25

#define PRINTF_DFL  120
#define PRINTF_DFL  130

struct mon_event_text {
	struct list_head e_link;
@@ -33,7 +38,9 @@ struct mon_event_text {
	unsigned int tstamp;
	int length;		/* Depends on type: xfer length or act length */
	int status;
	char setup_flag;
	char data_flag;
	unsigned char setup[SETUP_MAX];
	unsigned char data[DATA_MAX];
};

@@ -64,6 +71,22 @@ static void mon_text_dtor(void *, kmem_cache_t *, unsigned long);
 * This is called with the whole mon_bus locked, so no additional lock.
 */

static inline char mon_text_get_setup(struct mon_event_text *ep,
    struct urb *urb, char ev_type)
{

	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
		return '-';

	if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
		return 'D';
	if (urb->setup_packet == NULL)
		return 'Z';	/* '0' would be not as pretty. */

	memcpy(ep->setup, urb->setup_packet, SETUP_MAX);
	return 0;
}

static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
    int len, char ev_type)
{
@@ -90,7 +113,6 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,

	/*
	 * Bulk is easy to shortcut reliably. 
	 * XXX Control needs setup packet taken.
	 * XXX Other pipe types need consideration. Currently, we overdo it
	 * and collect garbage for them: better more than less.
	 */
@@ -144,6 +166,7 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
	/* Collecting status makes debugging sense for submits, too */
	ep->status = urb->status;

	ep->setup_flag = mon_text_get_setup(ep, urb, ev_type);
	ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type);

	rp->nevents++;
@@ -299,10 +322,25 @@ static ssize_t mon_text_read(struct file *file, char __user *buf,
	default: /* PIPE_BULK */  utype = 'B';
	}
	cnt += snprintf(pbuf + cnt, limit - cnt,
	    "%lx %u %c %c%c:%03u:%02u %d %d",
	    "%lx %u %c %c%c:%03u:%02u",
	    ep->id, ep->tstamp, ep->type,
	    utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe),
	    ep->status, ep->length);
	    utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));

	if (ep->setup_flag == 0) {   /* Setup packet is present and captured */
		cnt += snprintf(pbuf + cnt, limit - cnt,
		    " s %02x %02x %04x %04x %04x",
		    ep->setup[0],
		    ep->setup[1],
		    (ep->setup[3] << 8) | ep->setup[2],
		    (ep->setup[5] << 8) | ep->setup[4],
		    (ep->setup[7] << 8) | ep->setup[6]);
	} else if (ep->setup_flag != '-') { /* Unable to capture setup packet */
		cnt += snprintf(pbuf + cnt, limit - cnt,
		    " %c __ __ ____ ____ ____", ep->setup_flag);
	} else {                     /* No setup for this kind of URB */
		cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->status);
	}
	cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->length);

	if ((data_len = ep->length) > 0) {
		if (ep->data_flag == 0) {