Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the tools applications of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include "serenum.h" |
43 | #include <QByteArray> |
44 | #include <QString> |
45 | #include <QDebug> |
46 | #include <QFileInfo> |
47 | #include <QDir> |
48 | |
49 | #include <usb.h> |
50 | |
51 | class InterfaceInfo |
52 | { |
53 | public: |
54 | InterfaceInfo(const QString &mf, const QString &pr, int mfid, int prid); |
55 | QString manufacturer; |
56 | QString product; |
57 | int manufacturerid; |
58 | int productid; |
59 | }; |
60 | |
61 | InterfaceInfo::InterfaceInfo(const QString &mf, const QString &pr, int mfid, int prid) : |
62 | manufacturer(mf), |
63 | product(pr), |
64 | manufacturerid(mfid), |
65 | productid(prid) |
66 | { |
67 | if(mf.isEmpty()) |
68 | manufacturer = QString("[%1]").arg(mfid, 4, 16, QChar( |
69 | if(pr.isEmpty()) |
70 | product = QString("[%1]").arg(prid, 4, 16, QChar( |
71 | } |
72 | |
73 | QList<SerialPortId> enumerateSerialPorts(int loglevel) |
74 | { |
75 | QList<QString> eligibleInterfaces; |
76 | QList<InterfaceInfo> eligibleInterfacesInfo; |
77 | QList<SerialPortId> list; |
78 | |
79 | usb_init(); |
80 | usb_find_busses(); |
81 | usb_find_devices(); |
82 | |
83 | for (struct usb_bus *bus = usb_get_busses(); bus; bus = bus->next) { |
84 | for (struct usb_device *device = bus->devices; device; device = device->next) { |
85 | for (int n = 0; n < device->descriptor.bNumConfigurations && device->config; ++n) { |
86 | struct usb_config_descriptor &usbConfig =device->config[n]; |
87 | QList<int> usableInterfaces; |
88 | for (int m = 0; m < usbConfig.bNumInterfaces; ++m) { |
89 | for (int o = 0; o < usbConfig.interface[m].num_altsetting; ++o) { |
90 | struct usb_interface_descriptor &descriptor = usbConfig.interface[m].altsetting[o]; |
91 | if (descriptor.bInterfaceClass != 2 // "Communication" |
92 | || descriptor.bInterfaceSubClass != 2 // Abstract (modem) |
93 | || descriptor.bInterfaceProtocol != 255) // Vendor Specific |
94 | continue; |
95 | |
96 | unsigned char *buf = descriptor.extra; |
97 | unsigned int size = descriptor.extralen; |
98 | while (size >= 2 * sizeof(u_int8_t)) { |
99 | // for Communication devices there is a slave interface for the actual |
100 | // data transmission. |
101 | // the extra info stores that as a index for the interface |
102 | if (buf[0] >= 5 && buf[1] == 36 && buf[2] == 6) { // CDC Union |
103 | for (int i = 3; i < buf[0]; i++) |
104 | usableInterfaces.append((int) buf[i]); |
105 | } |
106 | size -= buf[0]; |
107 | buf += buf[0]; |
108 | } |
109 | } |
110 | } |
111 | |
112 | if (usableInterfaces.isEmpty()) |
113 | continue; |
114 | |
115 | QString manufacturerString; |
116 | QString productString; |
117 | |
118 | usb_dev_handle *devh = usb_open(device); |
119 | if (devh) { |
120 | QByteArray buf; |
121 | buf.resize(256); |
122 | int err = usb_get_string_simple(devh, device->descriptor.iManufacturer, buf.data(), buf.size()); |
123 | if (err < 0) { |
124 | if (loglevel > 1) |
125 | qDebug() << " can't read manufacturer name, error:"<< err; |
126 | } else { |
127 | manufacturerString = QString::fromAscii(buf); |
128 | if (loglevel > 1) |
129 | qDebug() << " manufacturer:"<< manufacturerString; |
130 | } |
131 | |
132 | buf.resize(256); |
133 | err = usb_get_string_simple(devh, device->descriptor.iProduct, buf.data(), buf.size()); |
134 | if (err < 0) { |
135 | if (loglevel > 1) |
136 | qDebug() << " can't read product name, error:"<< err; |
137 | } else { |
138 | productString = QString::fromAscii(buf); |
139 | if (loglevel > 1) |
140 | qDebug() << " product:"<< productString; |
141 | } |
142 | usb_close(devh); |
143 | } else if (loglevel > 0) { |
144 | qDebug() << " can't open usb device"; |
145 | } |
146 | |
147 | // second loop to find the actual data interface. |
148 | foreach (int i, usableInterfaces) { |
149 | #ifdef Q_OS_MAC |
150 | eligibleInterfaces << QString("^cu\\.usbmodem.*%1$") |
151 | .arg(QString("%1").arg(i, 1, 16).toUpper()); |
152 | eligibleInterfacesInfo << InterfaceInfo(manufacturerString, productString, device->descriptor.idVendor, device->descriptor.idProduct); |
153 | #else |
154 | // ### manufacturer and product strings are only readable as root :( |
155 | if (!manufacturerString.isEmpty() && !productString.isEmpty()) { |
156 | eligibleInterfaces << QString("usb-%1_%2-if%3") |
157 | .arg(manufacturerString.replace(QChar( |
158 | .arg(productString.replace(QChar( |
159 | .arg(i, 2, 16, QChar( |
160 | } else { |
161 | eligibleInterfaces << QString("if%1").arg(i, 2, 16, QChar( |
162 | } |
163 | #endif |
164 | } |
165 | #ifndef Q_OS_MAC |
166 | // On mac, we need a 1-1 mapping between eligibleInterfaces and eligibleInterfacesInfo |
167 | // in order to find the friendly name for an interface |
168 | eligibleInterfacesInfo << InterfaceInfo(manufacturerString, productString, device->descriptor.idVendor, device->descriptor.idProduct); |
169 | #endif |
170 | } |
171 | } |
172 | } |
173 | |
174 | if (loglevel > 1) |
175 | qDebug() << " searching for interfaces:"<< eligibleInterfaces; |
176 | |
177 | #ifdef Q_OS_MAC |
178 | QDir dir("/dev/"); |
179 | bool allowAny = false; |
180 | #else |
181 | QDir dir("/dev/serial/by-id/"); |
182 | bool allowAny = eligibleInterfaces.isEmpty(); |
183 | #endif |
184 | foreach (const QFileInfo &info, dir.entryInfoList(QDir::System)) { |
185 | if (!info.isDir()) { |
186 | bool usable = allowAny; |
187 | QString friendlyName = info.fileName(); |
188 | foreach (const QString &iface, eligibleInterfaces) { |
189 | if (info.fileName().contains(QRegExp(iface))) { |
190 | if (loglevel > 1) |
191 | qDebug() << " found device file:"<< info.fileName() << endl; |
192 | #ifdef Q_OS_MAC |
193 | InterfaceInfo info = eligibleInterfacesInfo[eligibleInterfaces.indexOf(iface)]; |
194 | friendlyName = info.manufacturer + " "+ info.product; |
195 | #endif |
196 | usable = true; |
197 | break; |
198 | } |
199 | } |
200 | if (!usable) |
201 | continue; |
202 | |
203 | SerialPortId id; |
204 | id.friendlyName = friendlyName; |
205 | id.portName = info.canonicalFilePath(); |
206 | list << id; |
207 | } |
208 | } |
209 | |
210 | if (list.isEmpty() && !eligibleInterfacesInfo.isEmpty() && loglevel > 0) { |
211 | qDebug() << "Possible USB devices found, but without serial drivers:"; |
212 | foreach(const InterfaceInfo &iface, eligibleInterfacesInfo) { |
213 | qDebug() << " Manufacturer:" |
214 | << iface.manufacturer |
215 | << "Product:" |
216 | << iface.product |
217 | #ifdef Q_OS_LINUX |
218 | << endl |
219 | << " Load generic driver using:" |
220 | << QString("sudo modprobe usbserial vendor=0x%1 product=0x%2") |
221 | .arg(iface.manufacturerid, 4, 16, QChar( |
222 | .arg(iface.productid, 4, 16, QChar( |
223 | #else |
224 | ; |
225 | #endif |
226 | } |
227 | } |
228 | return list; |
229 | } |
230 | |
231 |
Warning: That file was not part of the compilation database. It may have many parsing errors.