[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>
This commit is contained in:
parent
ead99eb001
commit
ae0d6cceb2
@ -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:
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user