Refactor USB vendor/product to product string to UsbUtil.h.

Also implement reading of /var/lib/usbutils/usb.ids for systems that
have it (e.g. desktop Linux).
This commit is contained in:
Peter Johnson
2016-12-21 00:14:55 -08:00
parent 88afefe464
commit 10b13da3da
3 changed files with 182 additions and 40 deletions

View File

@@ -38,6 +38,7 @@
#include "Handle.h"
#include "Log.h"
#include "Notifier.h"
#include "UsbUtil.h"
using namespace cs;
@@ -308,10 +309,59 @@ static int SetStringCtrlIoctl(int fd, int id, int maximum,
return DoIoctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
}
static bool GetDescriptionSysV4L(llvm::StringRef path, std::string* desc) {
llvm::SmallString<64> ifpath{"/sys/class/video4linux/"};
ifpath += path.substr(5);
ifpath += "/device/interface";
int fd = open(ifpath.c_str(), O_RDONLY);
if (fd < 0) return false;
char readBuf[128];
ssize_t n = read(fd, readBuf, sizeof(readBuf));
close(fd);
if (n <= 0) return false;
*desc = llvm::StringRef(readBuf, n).rtrim();
return true;
}
static bool GetDescriptionIoctl(const char* cpath, std::string* desc) {
int fd = open(cpath, O_RDWR);
if (fd < 0) return false;
struct v4l2_capability vcap;
std::memset(&vcap, 0, sizeof(vcap));
if (DoIoctl(fd, VIDIOC_QUERYCAP, &vcap) < 0) {
close(fd);
return false;
}
close(fd);
llvm::StringRef card{reinterpret_cast<const char*>(vcap.card)};
// try to convert "UVC Camera (0000:0000)" into a better name
int vendor = 0;
int product = 0;
if (card.startswith("UVC Camera (") &&
!card.substr(12, 4).getAsInteger(16, vendor) &&
!card.substr(17, 4).getAsInteger(16, product)) {
llvm::SmallString<64> card2Buf;
llvm::StringRef card2 = GetUsbNameFromId(vendor, product, card2Buf);
if (!card2.empty()) {
*desc = card2;
return true;
}
}
*desc = card;
return true;
}
static std::string GetDescriptionImpl(const char* cpath) {
llvm::StringRef path{cpath};
int fd;
char pathBuf[128];
std::string rv;
// If trying to get by id or path, follow symlink
if (path.startswith("/dev/v4l/by-id/")) {
@@ -324,48 +374,11 @@ static std::string GetDescriptionImpl(const char* cpath) {
if (path.startswith("/dev/video")) {
// Sometimes the /sys tree gives a better name.
llvm::SmallString<64> ifpath{"/sys/class/video4linux/"};
ifpath += path.substr(5);
ifpath += "/device/interface";
fd = open(ifpath.c_str(), O_RDONLY);
if (fd >= 0) {
char readBuf[128];
ssize_t n = read(fd, readBuf, sizeof(readBuf));
if (n > 0) {
close(fd);
return llvm::StringRef(readBuf, n).rtrim();
}
close(fd);
}
if (GetDescriptionSysV4L(path, &rv)) return rv;
}
// Otherwise use an ioctl to query the caps and get the card name
fd = open(cpath, O_RDWR);
if (fd >= 0) {
struct v4l2_capability vcap;
std::memset(&vcap, 0, sizeof(vcap));
if (DoIoctl(fd, VIDIOC_QUERYCAP, &vcap) >= 0) {
close(fd);
llvm::StringRef card{reinterpret_cast<const char*>(vcap.card)};
// try to convert "UVC Camera (0000:0000)" into a better name
int vendor = 0;
int product = 0;
if (card.startswith("UVC Camera (") &&
!card.substr(12, 4).getAsInteger(16, vendor) &&
!card.substr(17, 4).getAsInteger(16, product)) {
switch (vendor) {
case 0x046d:
switch (product) {
case 0x081b: return "Logitech, Inc. Webcam C310";
case 0x0825: return "Logitech, Inc. Webcam C270";
}
break;
}
}
return card;
}
close(fd);
}
if (GetDescriptionIoctl(cpath, &rv)) return rv;
return std::string{};
}

108
src/UsbUtil.cpp Normal file
View File

@@ -0,0 +1,108 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2016. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "UsbUtil.h"
#include <fcntl.h>
#include "llvm/Format.h"
#include "llvm/SmallString.h"
#include "llvm/raw_ostream.h"
#include "support/raw_istream.h"
#include "HttpUtil.h"
namespace cs {
static llvm::StringRef GetUsbNameFromFile(int vendor, int product,
llvm::SmallVectorImpl<char>& buf) {
int fd = open("/var/lib/usbutils/usb.ids", O_RDONLY);
if (fd < 0) return llvm::StringRef{};
llvm::raw_svector_ostream os{buf};
wpi::raw_fd_istream is{fd, true};
// build vendor and product 4-char hex strings
llvm::SmallString<16> vendorStr, productStr;
llvm::raw_svector_ostream vendorOs{vendorStr}, productOs{productStr};
vendorOs << llvm::format_hex_no_prefix(vendor, 4);
productOs << llvm::format_hex_no_prefix(product, 4);
// scan file
llvm::SmallString<128> lineBuf;
bool foundVendor = false;
for (;;) {
bool error = false;
auto line = ReadLine(is, lineBuf, 4096, &error);
if (error) break;
if (line.empty()) continue;
// look for vendor at start of line
if (line.startswith(vendorStr)) {
foundVendor = true;
os << line.substr(5).trim() << ' ';
continue;
}
if (foundVendor) {
// next vendor, but didn't match product?
if (line[0] != '\t') {
os << "Unknown";
return os.str();
}
// look for product
if (line.substr(1).startswith(productStr)) {
os << line.substr(6).trim();
return os.str();
}
}
}
return llvm::StringRef{};
}
llvm::StringRef GetUsbNameFromId(int vendor, int product,
llvm::SmallVectorImpl<char>& buf) {
// try reading usb.ids
llvm::StringRef rv = GetUsbNameFromFile(vendor, product, buf);
if (!rv.empty()) return rv;
// Fall back to internal database
llvm::raw_svector_ostream os{buf};
switch (vendor) {
case 0x046d:
os << "Logitech, Inc. ";
switch (product) {
case 0x0802: os << "Webcam C200"; break;
case 0x0804: os << "Webcam C250"; break;
case 0x0805: os << "Webcam C300"; break;
case 0x0807: os << "Webcam B500"; break;
case 0x0808: os << "Webcam C600"; break;
case 0x0809: os << "Webcam Pro 9000"; break;
case 0x080a: os << "Portable Webcam C905"; break;
case 0x080f: os << "Webcam C120"; break;
case 0x0819: os << "Webcam C210"; break;
case 0x081b: os << "Webcam C310"; break;
case 0x081d: os << "HD Webcam C510"; break;
case 0x0821: os << "HD Webcam C910"; break;
case 0x0825: os << "Webcam C270"; break;
case 0x0826: os << "HD Webcam C525"; break;
case 0x0828: os << "HD Webcam B990"; break;
case 0x082b: os << "Webcam C170"; break;
case 0x082d: os << "HD Pro Webcam C920"; break;
case 0x0836: os << "B525 HD Webcam"; break;
case 0x0843: os << "Webcam C930e"; break;
}
break;
}
return os.str();
}
} // namespace cs

21
src/UsbUtil.h Normal file
View File

@@ -0,0 +1,21 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2016. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#ifndef CS_USBUTIL_H_
#define CS_USBUTIL_H_
#include "llvm/SmallVector.h"
#include "llvm/StringRef.h"
namespace cs {
llvm::StringRef GetUsbNameFromId(int vendor, int product,
llvm::SmallVectorImpl<char>& buf);
} // namespace cs
#endif // CS_USBUTIL_H_