ecfd158bab7862a50de2120654ccc3022dc8c348
[platform/framework/web/crosswalk.git] / src / tools / telemetry / third_party / pyserial / serial / tools / list_ports_linux.py
1 #!/usr/bin/env python
2
3 # portable serial port access with python
4 #
5 # This is a module that gathers a list of serial ports including details on
6 # GNU/Linux systems
7 #
8 # (C) 2011-2013 Chris Liechti <cliechti@gmx.net>
9 # this is distributed under a free software license, see license.txt
10
11 import glob
12 import sys
13 import os
14 import re
15
16 try:
17     import subprocess
18 except ImportError:
19     def popen(argv):
20         try:
21             si, so =  os.popen4(' '.join(argv))
22             return so.read().strip()
23         except:
24             raise IOError('lsusb failed')
25 else:
26     def popen(argv):
27         try:
28             return subprocess.check_output(argv, stderr=subprocess.STDOUT).strip()
29         except:
30             raise IOError('lsusb failed')
31
32
33 # The comports function is expected to return an iterable that yields tuples of
34 # 3 strings: port name, human readable description and a hardware ID.
35 #
36 # as currently no method is known to get the second two strings easily, they
37 # are currently just identical to the port name.
38
39 # try to detect the OS so that a device can be selected...
40 plat = sys.platform.lower()
41
42 def read_line(filename):
43     """help function to read a single line from a file. returns none"""
44     try:
45         f = open(filename)
46         line = f.readline().strip()
47         f.close()
48         return line
49     except IOError:
50         return None
51
52 def re_group(regexp, text):
53     """search for regexp in text, return 1st group on match"""
54     if sys.version < '3':
55         m = re.search(regexp, text)
56     else:
57         # text is bytes-like
58         m = re.search(regexp, text.decode('ascii', 'replace'))
59     if m: return m.group(1)
60
61
62 # try to extract descriptions from sysfs. this was done by experimenting,
63 # no guarantee that it works for all devices or in the future...
64
65 def usb_sysfs_hw_string(sysfs_path):
66     """given a path to a usb device in sysfs, return a string describing it"""
67     bus, dev = os.path.basename(os.path.realpath(sysfs_path)).split('-')
68     snr = read_line(sysfs_path+'/serial')
69     if snr:
70         snr_txt = ' SNR=%s' % (snr,)
71     else:
72         snr_txt = ''
73     return 'USB VID:PID=%s:%s%s' % (
74             read_line(sysfs_path+'/idVendor'),
75             read_line(sysfs_path+'/idProduct'),
76             snr_txt
77             )
78
79 def usb_lsusb_string(sysfs_path):
80     base = os.path.basename(os.path.realpath(sysfs_path))
81     bus = base.split('-')[0]
82     try:
83         dev = int(read_line(os.path.join(sysfs_path, 'devnum')))
84         desc = popen(['lsusb', '-v', '-s', '%s:%s' % (bus, dev)])
85         # descriptions from device
86         iManufacturer = re_group('iManufacturer\s+\w+ (.+)', desc)
87         iProduct = re_group('iProduct\s+\w+ (.+)', desc)
88         iSerial = re_group('iSerial\s+\w+ (.+)', desc) or ''
89         # descriptions from kernel
90         idVendor = re_group('idVendor\s+0x\w+ (.+)', desc)
91         idProduct = re_group('idProduct\s+0x\w+ (.+)', desc)
92         # create descriptions. prefer text from device, fall back to the others
93         return '%s %s %s' % (iManufacturer or idVendor, iProduct or idProduct, iSerial)
94     except IOError:
95         return base
96
97 def describe(device):
98     """\
99     Get a human readable description.
100     For USB-Serial devices try to run lsusb to get a human readable description.
101     For USB-CDC devices read the description from sysfs.
102     """
103     base = os.path.basename(device)
104     # USB-Serial devices
105     sys_dev_path = '/sys/class/tty/%s/device/driver/%s' % (base, base)
106     if os.path.exists(sys_dev_path):
107         sys_usb = os.path.dirname(os.path.dirname(os.path.realpath(sys_dev_path)))
108         return usb_lsusb_string(sys_usb)
109     # USB-CDC devices
110     sys_dev_path = '/sys/class/tty/%s/device/interface' % (base,)
111     if os.path.exists(sys_dev_path):
112         return read_line(sys_dev_path)
113
114     # USB Product Information
115     sys_dev_path = '/sys/class/tty/%s/device' % (base,)
116     if os.path.exists(sys_dev_path):
117         product_name_file = os.path.dirname(os.path.realpath(sys_dev_path)) + "/product"
118         if os.path.exists(product_name_file):
119             return read_line(product_name_file)
120
121     return base
122
123 def hwinfo(device):
124     """Try to get a HW identification using sysfs"""
125     base = os.path.basename(device)
126     if os.path.exists('/sys/class/tty/%s/device' % (base,)):
127         # PCI based devices
128         sys_id_path = '/sys/class/tty/%s/device/id' % (base,)
129         if os.path.exists(sys_id_path):
130             return read_line(sys_id_path)
131         # USB-Serial devices
132         sys_dev_path = '/sys/class/tty/%s/device/driver/%s' % (base, base)
133         if os.path.exists(sys_dev_path):
134             sys_usb = os.path.dirname(os.path.dirname(os.path.realpath(sys_dev_path)))
135             return usb_sysfs_hw_string(sys_usb)
136         # USB-CDC devices
137         if base.startswith('ttyACM'):
138             sys_dev_path = '/sys/class/tty/%s/device' % (base,)
139             if os.path.exists(sys_dev_path):
140                 return usb_sysfs_hw_string(sys_dev_path + '/..')
141     return 'n/a'    # XXX directly remove these from the list?
142
143 def comports():
144     devices = glob.glob('/dev/ttyS*') + glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*')
145     return [(d, describe(d), hwinfo(d)) for d in devices]
146
147 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
148 # test
149 if __name__ == '__main__':
150     for port, desc, hwid in sorted(comports()):
151         print "%s: %s [%s]" % (port, desc, hwid)