Last active
August 29, 2015 14:03
-
-
Save amitu/ba847556c57d73623f8e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from path import path | |
from struct import unpack | |
from collections import namedtuple | |
import stat, os | |
USBDeviceDescriptor = namedtuple( | |
"USBDeviceDescriptor", " ".join( | |
[ | |
"bLength", | |
"bDescriptorType", | |
"bcdUSB", | |
"bDeviceClass", | |
"bDeviceSubClass", | |
"bDeviceProtocol", | |
"bMaxPacketSize0", | |
"idVendor", | |
"idProduct", | |
"bcdDevice", | |
"iManufacturer", | |
"iProduct", | |
"iSerialNumber", | |
"bNumConfigurations", | |
] | |
) | |
) | |
USBConfigDescriptor = namedtuple( | |
"USBConfigDescriptor", " ".join( | |
[ | |
"bLength", | |
"bDescriptorType", | |
"wTotalLength", | |
"bNumInterfaces", | |
"bConfigurationValue", | |
"iConfiguration", | |
"bmAttributes", | |
"bMaxPower", | |
] | |
) | |
) | |
USBInterfaceDescriptor = namedtuple( | |
"USBInterfaceDescriptor", " ".join( | |
[ | |
"bLength", | |
"bDescriptorType", | |
"bInterfaceNumber", | |
"bAlternateSetting", | |
"bNumEndpoints", | |
"bInterfaceClass", | |
"bInterfaceSubClass", | |
"bInterfaceProtocol", | |
"iInterface", | |
] | |
) | |
) | |
USBEndpointDescriptor = namedtuple( | |
"USBEndpointDescriptor", " ".join( | |
[ | |
"bLength", | |
"bDescriptorType", | |
"bEndpointAddress", | |
"bmAttributes", | |
"wMaxPacketSize", | |
"bInterval", | |
# "bRefresh", | |
# "bSynchAddress", | |
] | |
) | |
) | |
USBDevFSCtrlTransfer = namedtuple( | |
"USBDevFSCtrlTransfer", " ".join( | |
[ | |
"bRequestType", | |
"bRequest", | |
"wValue", | |
"wIndex", | |
"wLength", | |
"timeout", | |
] | |
) | |
) | |
# struct usbdevfs_ctrltransfer { | |
# 40 __u8 bRequestType; | |
# 41 __u8 bRequest; | |
# 42 __u16 wValue; | |
# 43 __u16 wIndex; | |
# 44 __u16 wLength; | |
# 45 __u32 timeout; /* in milliseconds */ | |
# 46 void __user *data; | |
# 47 }; | |
USBDeviceDescriptor_Format = "<BBHBBBBHHHBBBB" | |
USB_DT_DEVICE_SIZE = 18 | |
USBConfigDescriptor_Format = "<BBHBBBBB" | |
USB_DT_CONFIG_SIZE = 9 | |
USBInterfaceDescriptor_Format = "<BBBBBBBBB" | |
USB_DT_INTERFACE_SIZE = 9 | |
USBEndpointDescriptor_Format = "<BBBBHB" | |
USB_DT_ENDPOINT_SIZE = 7 | |
USB_DT_DEVICE = 1 | |
USB_DT_CONFIG = 2 | |
USB_DT_INTERFACE = 4 | |
USB_DT_ENDPOINT = 5 | |
USB_ENDPOINT_XFER_BULK = 2 | |
USB_ENDPOINT_DIR_MASK = 0x80 | |
VENDOR_IDS = """ | |
#define VENDOR_ID_ACER 0x0502 | |
#define VENDOR_ID_ALLWINNER 0x1F3A | |
#define VENDOR_ID_AMLOGIC 0x1b8e | |
#define VENDOR_ID_ANYDATA 0x16D5 | |
#define VENDOR_ID_ARCHOS 0x0E79 | |
#define VENDOR_ID_ASUS 0x0b05 | |
#define VENDOR_ID_BYD 0x1D91 | |
#define VENDOR_ID_COMPAL 0x04B7 | |
#define VENDOR_ID_COMPALCOMM 0x1219 | |
#define VENDOR_ID_DELL 0x413c | |
#define VENDOR_ID_ECS 0x03fc | |
#define VENDOR_ID_EMERGING_TECH 0x297F | |
#define VENDOR_ID_EMERSON 0x2207 | |
#define VENDOR_ID_FOXCONN 0x0489 | |
#define VENDOR_ID_FUJITSU 0x04C5 | |
#define VENDOR_ID_FUNAI 0x0F1C | |
#define VENDOR_ID_GARMIN_ASUS 0x091E | |
#define VENDOR_ID_GIGABYTE 0x0414 | |
#define VENDOR_ID_GIGASET 0x1E85 | |
#define VENDOR_ID_GOOGLE 0x18d1 | |
#define VENDOR_ID_HAIER 0x201E | |
#define VENDOR_ID_HARRIS 0x19A5 | |
#define VENDOR_ID_HISENSE 0x109b | |
#define VENDOR_ID_HP 0x03f0 | |
#define VENDOR_ID_HTC 0x0bb4 | |
#define VENDOR_ID_HUAWEI 0x12D1 | |
#define VENDOR_ID_INQ_MOBILE 0x2314 | |
#define VENDOR_ID_INTEL 0x8087 | |
#define VENDOR_ID_INTERMEC 0x067e | |
#define VENDOR_ID_IRIVER 0x2420 | |
#define VENDOR_ID_K_TOUCH 0x24E3 | |
#define VENDOR_ID_KT_TECH 0x2116 | |
#define VENDOR_ID_KOBO 0x2237 | |
#define VENDOR_ID_KYOCERA 0x0482 | |
#define VENDOR_ID_LAB126 0x1949 | |
#define VENDOR_ID_LENOVO 0x17EF | |
#define VENDOR_ID_LENOVOMOBILE 0x2006 | |
#define VENDOR_ID_LGE 0x1004 | |
#define VENDOR_ID_LUMIGON 0x25E3 | |
#define VENDOR_ID_MOTOROLA 0x22b8 | |
#define VENDOR_ID_MSI 0x0DB0 | |
#define VENDOR_ID_MTK 0x0e8d | |
#define VENDOR_ID_NEC 0x0409 | |
#define VENDOR_ID_NOOK 0x2080 | |
#define VENDOR_ID_NVIDIA 0x0955 | |
#define VENDOR_ID_OPPO 0x22D9 | |
#define VENDOR_ID_OTGV 0x2257 | |
#define VENDOR_ID_OUYA 0x2836 | |
#define VENDOR_ID_PANTECH 0x10A9 | |
#define VENDOR_ID_PEGATRON 0x1D4D | |
#define VENDOR_ID_PHILIPS 0x0471 | |
#define VENDOR_ID_PMC 0x04DA | |
#define VENDOR_ID_POSITIVO 0x1662 | |
#define VENDOR_ID_PRESTIGIO 0x29e4 | |
#define VENDOR_ID_QISDA 0x1D45 | |
#define VENDOR_ID_QUALCOMM 0x05c6 | |
#define VENDOR_ID_QUANTA 0x0408 | |
#define VENDOR_ID_ROCKCHIP 0x2207 | |
#define VENDOR_ID_SAMSUNG 0x04e8 | |
#define VENDOR_ID_SHARP 0x04dd | |
#define VENDOR_ID_SK_TELESYS 0x1F53 | |
#define VENDOR_ID_SONY 0x054C | |
#define VENDOR_ID_SONY_ERICSSON 0x0FCE | |
#define VENDOR_ID_T_AND_A 0x1BBB | |
#define VENDOR_ID_TECHFAITH 0x1d09 | |
#define VENDOR_ID_TELEEPOCH 0x2340 | |
#define VENDOR_ID_TI 0x0451 | |
#define VENDOR_ID_TOSHIBA 0x0930 | |
#define VENDOR_ID_UNOWHY 0x2A49 | |
#define VENDOR_ID_VIZIO 0xE040 | |
#define VENDOR_ID_WACOM 0x0531 | |
#define VENDOR_ID_XIAOMI 0x2717 | |
#define VENDOR_ID_YOTADEVICES 0x2916 | |
#define VENDOR_ID_YULONG_COOLPAD 0x1EBF | |
#define VENDOR_ID_ZTE 0x19D2 | |
""".split("\n") | |
VENDOR_IDS = dict( | |
( | |
eval(line.split()[2]), | |
line.split()[1][len("VENDOR_ID_"):] | |
) | |
for line in VENDOR_IDS if line.strip() | |
) | |
# print VENDOR_IDS | |
ADB_CLASS = 0xff | |
ADB_SUBCLASS = 0x42 | |
ADB_PROTOCOL = 0x1 | |
DEVICES = [] | |
class USB(object): | |
def __init__(self, fname, ep_in, ep_out, zero_mask): | |
self.fname = fname | |
self.ep_in = ep_in | |
self.ep_out = ep_out | |
self.zero_mask = zero_mask | |
self.writeable = True | |
self.mark = 0 | |
def __str__(self): | |
return "USB: %s" % self.__dict__ | |
def register_device( | |
devname, devpath, ep_in, ep_out, interface, serial_index, zero | |
): | |
# print "register_device", devname, devpath, ep_in, ep_out, interface, zero | |
usb = USB(devname, ep_in, ep_out, zero) | |
usb.mark = 1 | |
DEVICES.append(usb) | |
# print usb | |
try: | |
usb.desc = os.open(devname, os.O_RDWR) | |
except Exception, e: | |
print e, devname, "os.O_RDWR" | |
try: | |
usb.desc = os.open(devname, os.O_RDONLY) | |
except Exception, e: | |
print e, devname, "os.O_RDONLY" | |
return | |
else: | |
usb.writeable = False | |
if not serial_index: | |
return | |
def devices(): | |
for dev_dir in path("/dev/bus/usb").dirs(): | |
# print dev_dir | |
for dev_file in dev_dir.glob("*"): | |
# print dev_file | |
zero_mask = 0 | |
try: | |
fd = dev_file.open("r") | |
except IOError, e: | |
print e | |
continue | |
usb_info = fd.read() | |
fd.close() | |
# print "usb_info.len =", len(usb_info) | |
if len(usb_info) < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE: | |
print "desclength %s is too small" % len(usb_info) | |
continue | |
device = USBDeviceDescriptor._make( | |
unpack( | |
USBDeviceDescriptor_Format, | |
usb_info[:USB_DT_DEVICE_SIZE] | |
) | |
) | |
# devname = dev_dir.basename() + "/" + dev_file.basename() | |
devname = dev_file.abspath() | |
# print device | |
if ( | |
(device.bLength != USB_DT_DEVICE_SIZE) or | |
(device.bDescriptorType != USB_DT_DEVICE) | |
): | |
print "bad device" | |
continue | |
vid = device.idVendor | |
if vid not in VENDOR_IDS: | |
# print "VID: %s not in VENDOR_IDS" % vid | |
continue | |
# print "VID valid", VENDOR_IDS[vid] | |
# pid = device.idProduct | |
# print "[ %s is V:%04x P:%04x ]" % (devname, vid, pid) | |
usb_info = usb_info[USB_DT_DEVICE_SIZE:] | |
config = USBConfigDescriptor._make( | |
unpack( | |
USBConfigDescriptor_Format, | |
usb_info[:USB_DT_CONFIG_SIZE] | |
) | |
) | |
# print config | |
if ( | |
(config.bLength != USB_DT_CONFIG_SIZE) or | |
(config.bDescriptorType != USB_DT_CONFIG) | |
): | |
print "usb_config_descriptor not found" | |
continue | |
usb_info = usb_info[USB_DT_CONFIG_SIZE:] | |
while usb_info: | |
length = ord(usb_info[0]) | |
type_ = ord(usb_info[1]) | |
if type_ != USB_DT_INTERFACE: | |
usb_info = usb_info[length:] | |
continue | |
interface = USBInterfaceDescriptor._make( | |
unpack( | |
USBInterfaceDescriptor_Format, | |
usb_info[:USB_DT_INTERFACE_SIZE] | |
) | |
) | |
usb_info = usb_info[length:] | |
if length != USB_DT_INTERFACE_SIZE: | |
print "interface descriptor has wrong size" | |
break | |
# print interface | |
# print ( | |
# "bInterfaceClass: %d, bInterfaceSubClass: %d, " + | |
# "bInterfaceProtocol: %d, bNumEndpoints: %d\n" | |
# ) % ( | |
# interface.bInterfaceClass, interface.bInterfaceSubClass, | |
# interface.bInterfaceProtocol, interface.bNumEndpoints | |
# ) | |
if ( | |
not ( | |
interface.bNumEndpoints == 2 and | |
vid in VENDOR_IDS and | |
interface.bInterfaceClass == ADB_CLASS and | |
interface.bInterfaceSubClass == ADB_SUBCLASS and | |
interface.bInterfaceProtocol == ADB_PROTOCOL | |
) | |
): | |
# print "invalid interface" | |
continue | |
print "valid adb", VENDOR_IDS[vid], len(usb_info) | |
ep1 = USBEndpointDescriptor._make( | |
unpack( | |
USBEndpointDescriptor_Format, | |
usb_info[:USB_DT_ENDPOINT_SIZE] | |
) | |
) | |
usb_info = usb_info[USB_DT_ENDPOINT_SIZE:] | |
ep2 = USBEndpointDescriptor._make( | |
unpack( | |
USBEndpointDescriptor_Format, | |
usb_info[:USB_DT_ENDPOINT_SIZE] | |
) | |
) | |
usb_info = usb_info[USB_DT_INTERFACE_SIZE:] | |
if ( | |
usb_info or | |
ep1.bLength != USB_DT_ENDPOINT_SIZE or | |
ep1.bDescriptorType != USB_DT_ENDPOINT or | |
ep2.bLength != USB_DT_ENDPOINT_SIZE or | |
ep2.bDescriptorType != USB_DT_ENDPOINT | |
): | |
print "endpoints not found" | |
break | |
if ( | |
ep1.bmAttributes != USB_ENDPOINT_XFER_BULK or | |
ep2.bmAttributes != USB_ENDPOINT_XFER_BULK | |
): | |
print "bulk endpoints not found" | |
continue | |
if interface.bInterfaceProtocol == 0x01: | |
zero_mask = ep1.wMaxPacketSize - 1 | |
if ep1.bEndpointAddress & USB_ENDPOINT_DIR_MASK: | |
local_ep_in = ep1.bEndpointAddress | |
local_ep_out = ep2.bEndpointAddress | |
else: | |
local_ep_in = ep2.bEndpointAddress | |
local_ep_out = ep1.bEndpointAddress | |
st = dev_file.stat() | |
if stat.S_ISCHR(st.st_mode): | |
pathbuf = "/sys/dev/char/%s:%s" % ( | |
os.major(st.st_rdev), os.minor(st.st_rdev) | |
) | |
# print pathbuf, open(pathbuf + "/product").read(), | |
print "serial =", open(pathbuf + "/serial").read(), | |
link = os.readlink(pathbuf) | |
if link: | |
devpath = "usb:%s" % link.split("/")[-1] | |
else: | |
print dev_file, "is not a char device" | |
continue | |
register_device( | |
devname, devpath, local_ep_in, local_ep_out, interface, | |
device.iSerialNumber, zero_mask | |
) | |
def shell(cmd, device): | |
pass | |
def main(): | |
devices() | |
# shell("ls", DEVICES[0]) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment