#!/usr/bin/python # -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details: # # Copyright (C) 2011 Red Hat, Inc. # import binascii import string import sys import defs import wmc URBF_UNKNOWN = 0 URBF_GET_DESC = 1 URBF_SEL_CONF = 2 URBF_RESET_PIPE = 3 URBF_TRANSFER = 4 URBF_GET_STATUS = 5 URBF_CONTROL = 6 URBF_SET_FEATURE = 7 URBF_ABORT_PIPE = 8 funcs = { "-- URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:": (URBF_GET_DESC, False, None), "-- URB_FUNCTION_SELECT_CONFIGURATION:": (URBF_SEL_CONF, False, None), "-- URB_FUNCTION_RESET_PIPE:": (URBF_RESET_PIPE, False, None), "-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:": (URBF_TRANSFER, True, "T"), "-- URB_FUNCTION_GET_STATUS_FROM_DEVICE:": (URBF_GET_STATUS, False, None), "-- URB_FUNCTION_CONTROL_TRANSFER:": (URBF_CONTROL, True, "C"), "-- URB_FUNCTION_SET_FEATURE_TO_DEVICE:": (URBF_SET_FEATURE, False, None), "-- URB_FUNCTION_ABORT_PIPE:": (URBF_SET_FEATURE, False, None) } def get_urb_info(l): direction = defs.TO_UNKNOWN tsstr = "" if l[0] == '[': idx = l.find(" ms]") if idx <= 0: return (defs.TO_UNKNOWN, -1, -1) tsstr = l[1:idx] idx = string.find(l, ">>> URB ") if idx >= 0: direction = defs.TO_MODEM else: idx = string.find(l, "<<< URB ") if idx >= 0: direction = defs.TO_HOST else: return (defs.TO_UNKNOWN, -1, -1) # Yay, valid packet, grab URB number numstr = "" for c in l[idx + 9:]: if c.isdigit(): numstr = numstr + c else: break if not len(numstr): raise Exception("Failed to get URB number ('%s')" % l) return (direction, int(numstr), int(tsstr)) class Packet: def __init__(self, line, control_prot, transfer_prot): self.direction = defs.TO_UNKNOWN self.func = URBF_UNKNOWN self.control_prot = control_prot self.transfer_prot = transfer_prot self.data = None self.urbnum = 0 self.timestamp = 0 self.protocol = None self.has_data = False self.typecode = None self.lines = [] self.in_data = False self.data_complete = False self.tmpdata = "" self.fcomplete = None self.funpack = None self.fshow = None # Check if this is actually a packet self.lines.append(line) (self.direction, self.urbnum, self.timestamp) = get_urb_info(line) def add_line(self, line): line = line.strip() if not len(line): return self.lines.append(line) if line[0] == '[': # Usually the end of a packet, but if we need data from the next # packet keep going if self.has_data and not self.data_complete: return False return True if not self.typecode: # haven't gotten our "-- URB_FUNCTION_xxxx" line yet if line.find("-- URB_FUNCTION_") >= 0: try: (self.func, self.has_data, self.typecode) = funcs[line] except KeyError: raise KeyError("URB function %s not handled" % line) if self.func == URBF_TRANSFER: self.protocol = self.transfer_prot elif self.func == URBF_CONTROL: self.protocol = self.control_prot if self.protocol: exec "from %s import get_funcs" % self.protocol (self.fcomplete, self.funpack, self.fshow) = get_funcs() else: return False # not done; need more lines if line.find("TransferBufferMDL = ") >= 0 and self.has_data: self.in_data = True return False # not done; need more lines if line.find("UrbLink = ") >= 0: if self.in_data: self.in_data = False # special case: zero-length data means complete if len(self.tmpdata) == 0: self.data_complete = True return True if self.fcomplete: self.data_complete = self.fcomplete(self.tmpdata, self.direction) if self.data_complete: self.data = self.funpack(self.tmpdata, self.direction) return self.data_complete else: self.data = binascii.unhexlify(self.tmpdata) self.data_complete = True return False # not done; need more lines if self.in_data: if len(line) and not "no data supplied" in line: d = line[line.index(": ") + 2:] # get data alone self.tmpdata += d.replace(" ", "") return False # not done; need more lines def add_ascii(self, line, items): if len(line) < 53: line += " " * (53 - len(line)) for i in items: if chr(i) in string.printable and i >= 32: line += chr(i) else: line += "." return line def show(self): if not self.has_data or not self.data: return # Ignore URBF_TRANSFER packets that appear to be returning SetupPacket data if self.data == chr(0xa1) + chr(0x01) + chr(0x00) + chr(0x00) + chr(0x05) + chr(0x00) + chr(0x00) + chr(0x00): return offset = 0 items = [] printed = False line = "" prefix = "*" if self.direction == defs.TO_MODEM: prefix = ">" elif self.direction == defs.TO_HOST: prefix = "<" if self.typecode: prefix = prefix + " " + self.typecode + " " else: prefix = prefix + " " prefix_printed = False for i in self.data: printed = False line += " %02x" % ord(i) items.append(ord(i)) if len(items) % 16 == 0: output = "%04d: %s" % (offset, self.add_ascii(line, items)) if offset == 0: print prefix + output else: print " " + output line = "" items = [] printed = True offset += 16 prefix_printed = True if not printed: output = "%04d: %s" % (offset, self.add_ascii(line, items)) if prefix_printed: print " " + output else: print prefix + output print "" if self.fshow: self.fshow(self.data, " " * 8, self.direction)