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
51class InterfaceInfo
52{
53public:
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
61InterfaceInfo::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('0'));
69 if(pr.isEmpty())
70 product = QString("[%1]").arg(prid, 4, 16, QChar('0'));
71}
72
73QList<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(' '), QChar('_')))
158 .arg(productString.replace(QChar(' '), QChar('_')))
159 .arg(i, 2, 16, QChar('0'));
160 } else {
161 eligibleInterfaces << QString("if%1").arg(i, 2, 16, QChar('0')); // fix!
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('0'))
222 .arg(iface.productid, 4, 16, QChar('0'));
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.