Explorar o código

[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: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Pete Zaitcev %!s(int64=20) %!d(string=hai) anos
pai
achega
ae0d6cceb2
Modificáronse 2 ficheiros con 64 adicións e 13 borrados
  1. 21 8
      Documentation/usb/usbmon.txt
  2. 43 5
      drivers/usb/mon/mon_text.c

+ 21 - 8
Documentation/usb/usbmon.txt

@@ -101,6 +101,13 @@ Here is the list of words, from left to right:
   or 3 and 2 positions, correspondingly.
   or 3 and 2 positions, correspondingly.
 - URB Status. This field makes no sense for submissions, but is present
 - 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.
   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 Length. This is the actual length in the URB.
 - Data tag. The usbmon may not always capture data, even if length is nonzero.
 - Data tag. The usbmon may not always capture data, even if length is nonzero.
   Only if tag is '=', the data words are present.
   Only if tag is '=', the data words are present.
@@ -125,25 +132,31 @@ class ParsedLine {
 			String data_str = st.nextToken();
 			String data_str = st.nextToken();
 			int len = data_str.length() / 2;
 			int len = data_str.length() / 2;
 			int i;
 			int i;
+			int b;	// byte is signed, apparently?! XXX
 			for (i = 0; i < len; i++) {
 			for (i = 0; i < len; i++) {
-				data[data_len] = Byte.parseByte(
-				    data_str.substring(i*2, i*2 + 2),
-				    16);
+				// 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++;
 				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:
 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
 An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper
 to a storage device at address 5:
 to a storage device at address 5:

+ 43 - 5
drivers/usb/mon/mon_text.c

@@ -18,12 +18,17 @@
  */
  */
 #define DATA_MAX  32
 #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.
  * This limit exists to prevent OOMs when the user process stops reading.
  */
  */
 #define EVENT_MAX  25
 #define EVENT_MAX  25
 
 
-#define PRINTF_DFL  120
+#define PRINTF_DFL  130
 
 
 struct mon_event_text {
 struct mon_event_text {
 	struct list_head e_link;
 	struct list_head e_link;
@@ -33,7 +38,9 @@ struct mon_event_text {
 	unsigned int tstamp;
 	unsigned int tstamp;
 	int length;		/* Depends on type: xfer length or act length */
 	int length;		/* Depends on type: xfer length or act length */
 	int status;
 	int status;
+	char setup_flag;
 	char data_flag;
 	char data_flag;
+	unsigned char setup[SETUP_MAX];
 	unsigned char data[DATA_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.
  * 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,
 static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
     int len, char ev_type)
     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. 
 	 * Bulk is easy to shortcut reliably. 
-	 * XXX Control needs setup packet taken.
 	 * XXX Other pipe types need consideration. Currently, we overdo it
 	 * XXX Other pipe types need consideration. Currently, we overdo it
 	 * and collect garbage for them: better more than less.
 	 * 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 */
 	/* Collecting status makes debugging sense for submits, too */
 	ep->status = urb->status;
 	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);
 	ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type);
 
 
 	rp->nevents++;
 	rp->nevents++;
@@ -299,10 +322,25 @@ static ssize_t mon_text_read(struct file *file, char __user *buf,
 	default: /* PIPE_BULK */  utype = 'B';
 	default: /* PIPE_BULK */  utype = 'B';
 	}
 	}
 	cnt += snprintf(pbuf + cnt, limit - cnt,
 	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,
 	    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 ((data_len = ep->length) > 0) {
 		if (ep->data_flag == 0) {
 		if (ep->data_flag == 0) {