[PATCH] USB: Patch to make usbmon to print control setup packets
authorPete Zaitcev <zaitcev@redhat.com>
Sat, 25 Jun 2005 21:32:59 +0000 (14:32 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 12 Jul 2005 18:52:55 +0000 (11:52 -0700)
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>
Documentation/usb/usbmon.txt
drivers/usb/mon/mon_text.c

index 2f8431f92b77fe7f762a75386f20ca8a92fbf0ca..f1896ee3bb2abf97f9b09f811a16db6fe9f3d1d2 100644 (file)
@@ -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_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++;
                        }
                }
        }
 }
 
-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:
index 755a4570477fdeb5a5f3fd714df3a7500948903e..26266b30028eaacbd3d6a20d08c162e2a92c4794 100644 (file)
  */
 #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) {