opennx/LibUSB.cpp
2025-08-08 20:34:09 +02:00

267 lines
7.9 KiB
C++

// $Id: LibUSB.cpp 605 2011-02-22 04:00:58Z felfert $
//
// Copyright (C) 2006 The OpenNX Team
// Author: Fritz Elfert
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "LibUSB.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/defs.h"
#endif
#include "MyDynlib.h"
#include "LibUSB.h"
#include <wx/wfstream.h>
#include <wx/txtstrm.h>
#include <wx/log.h>
#include <wx/arrimpl.cpp>
#include "trace.h"
ENABLE_TRACE;
WX_DEFINE_OBJARRAY(ArrayOfUSBDevices);
#ifdef SUPPORT_USBIP
#include <usb.h>
typedef void (*Tusb_init)(void);
typedef int (*Tusb_find_busses)(void);
typedef int (*Tusb_find_devices)(void);
typedef struct usb_bus *(*Tusb_get_busses)(void);
typedef int (*Tusb_get_string_simple)(usb_dev_handle *dev, int index, char *buf,
size_t buflen);
typedef usb_dev_handle *(*Tusb_open)(struct usb_device *dev);
typedef int (*Tusb_close)(usb_dev_handle *dev);
#endif
USBDevice::USBDevice(int v, int p, unsigned char c) {
m_iVendor = v;
m_iProduct = p;
m_iClass = c;
}
wxString USBDevice::toString() {
wxString ret = wxString::Format(wxT("%d-%d %04X/%04X/%02X"),
(int)m_iBusNum, (int)m_iDevNum, (int)m_iVendor,
(int)m_iProduct, (int)m_iClass);
if (!m_sVendor.IsEmpty())
ret.Append(wxT(" ")).Append(m_sVendor);
if (!m_sProduct.IsEmpty())
ret.Append(wxT(" ")).Append(m_sProduct);
if (!m_sSerial.IsEmpty())
ret.Append(wxT(" #")).Append(m_sSerial);
return ret;
}
wxString USBDevice::toShortString() {
wxString ret = m_sVendor;
if ((!ret.IsEmpty()) && (!m_sProduct.IsEmpty()))
ret.Append(wxT(" "));
ret.Append(m_sProduct);
return ret;
}
#ifdef SUPPORT_USBIP
static wxString readSysfs(int bus, int dev, const wxString &attr)
{
wxLogNull nolog;
int i;
// Find the device with the specified devnum
for (i = 0; i < 16 ; ++i) {
wxString path(wxString::Format(wxT("/sys/bus/usb/devices/%d-%d/devnum"), bus, i));
wxFileInputStream fis(path);
wxTextInputStream tis(fis);
if (dev == tis.Read16S())
break;
}
// Read the attribute
wxString path(wxString::Format(wxT("/sys/bus/usb/devices/%d-%d/%s"), bus, i, attr.c_str()));
wxFileInputStream fis(path);
wxTextInputStream tis(fis);
return tis.ReadLine();
}
#endif
void USB::adddev(MyDynamicLibrary *dll, struct usb_device *dev, unsigned char dclass)
{
#ifdef SUPPORT_USBIP
usb_dev_handle *udev;
char string[256];
switch (dclass) {
case USB_CLASS_HUB:
case USB_CLASS_HID:
return;
}
wxDYNLIB_FUNCTION(Tusb_open, usb_open, *dll);
if (!pfnusb_open)
return;
wxDYNLIB_FUNCTION(Tusb_close, usb_close, *dll);
if (!pfnusb_close)
return;
wxDYNLIB_FUNCTION(Tusb_get_string_simple, usb_get_string_simple, *dll);
if (!pfnusb_get_string_simple)
return;
udev = pfnusb_open(dev);
if (!udev)
return;
USBDevice d(dev->descriptor.idVendor, dev->descriptor.idProduct, dclass);
if (dev->descriptor.iManufacturer) {
if (0 < pfnusb_get_string_simple(udev,
dev->descriptor.iManufacturer, string, sizeof(string)))
d.m_sVendor = wxConvUTF8.cMB2WX(string);
}
if (dev->descriptor.iProduct) {
if (0 < pfnusb_get_string_simple(udev,
dev->descriptor.iProduct, string, sizeof(string)))
d.m_sProduct = wxConvUTF8.cMB2WX(string);
}
if (dev->descriptor.iSerialNumber) {
if (0 < pfnusb_get_string_simple(udev,
dev->descriptor.iSerialNumber, string, sizeof(string)))
d.m_sSerial = wxConvUTF8.cMB2WX(string);
}
wxString tmp(dev->bus->dirname, wxConvUTF8);
long lval;
tmp.ToLong(&lval);
d.m_iBusNum = lval;
tmp = wxConvUTF8.cMB2WX(dev->filename);
tmp.ToLong(&lval);
d.m_iDevNum = lval;
// Try fallback to sysfs, if libusb could not read info due to
// permission problems.
if (d.m_sVendor.IsEmpty()) {
d.m_sVendor = readSysfs(d.m_iBusNum, d.m_iDevNum, wxT("manufacturer"));
}
if (d.m_sProduct.IsEmpty()) {
d.m_sProduct = readSysfs(d.m_iBusNum, d.m_iDevNum, wxT("product"));
}
if (d.m_sSerial.IsEmpty()) {
d.m_sSerial = readSysfs(d.m_iBusNum, d.m_iDevNum, wxT("serial"));
}
myLogTrace(MYTRACETAG, wxT("Device found: %s"), VMB(d.toString()));
m_aDevices.Add(d);
pfnusb_close(udev);
#else
wxUnusedVar(dll);
wxUnusedVar(dev);
wxUnusedVar(dclass);
#endif
}
void USB::usbscan(MyDynamicLibrary *dll)
{
#ifdef SUPPORT_USBIP
struct usb_bus *bus;
wxDYNLIB_FUNCTION(Tusb_find_busses, usb_find_busses, *dll);
if (!pfnusb_find_busses)
return;
wxDYNLIB_FUNCTION(Tusb_find_devices, usb_find_devices, *dll);
if (!pfnusb_find_devices)
return;
wxDYNLIB_FUNCTION(Tusb_get_busses, usb_get_busses, *dll);
if (!pfnusb_get_busses)
return;
pfnusb_find_busses();
pfnusb_find_devices();
for (bus = pfnusb_get_busses(); bus; bus = bus->next) {
struct usb_device *dev;
for (dev = bus->devices; dev; dev = dev->next) {
int devclass = dev->descriptor.bDeviceClass;
if ((devclass == USB_CLASS_PER_INTERFACE) && (dev->config)) {
for (int c = 0; c < dev->descriptor.bNumConfigurations; c++) {
struct usb_config_descriptor *cfg = &dev->config[c];
for (int i = 0; i < cfg->bNumInterfaces; i++) {
struct usb_interface *uif = &cfg->interface[i];
for (int ac = 0; ac < uif->num_altsetting; ac++)
adddev(dll, dev, uif->altsetting[ac].bInterfaceClass);
}
}
} else
adddev(dll, dev, devclass);
}
}
#else
wxUnusedVar(dll);
#endif
}
USB::USB() {
m_bAvailable = false;
#ifdef SUPPORT_USBIP
wxLogNull noerrors;
MyDynamicLibrary dll;
if (dll.Load(wxT("libusb"))) {
wxDYNLIB_FUNCTION(Tusb_init, usb_init, dll);
if (!pfnusb_init)
return;
wxDYNLIB_FUNCTION(Tusb_find_busses, usb_find_busses, dll);
if (!pfnusb_find_busses)
return;
wxDYNLIB_FUNCTION(Tusb_find_devices, usb_find_devices, dll);
if (!pfnusb_find_devices)
return;
wxDYNLIB_FUNCTION(Tusb_get_busses, usb_get_busses, dll);
if (!pfnusb_get_busses)
return;
wxDYNLIB_FUNCTION(Tusb_open, usb_open, dll);
if (!pfnusb_open)
return;
wxDYNLIB_FUNCTION(Tusb_close, usb_close, dll);
if (!pfnusb_close)
return;
wxDYNLIB_FUNCTION(Tusb_get_string_simple, usb_get_string_simple, dll);
if (!pfnusb_get_string_simple)
return;
pfnusb_init();
m_bAvailable = true;
usbscan(&dll);
}
#endif
}
ArrayOfUSBDevices USB::GetDevices() {
return m_aDevices;
}
bool USB::IsAvailable() {
myLogTrace(MYTRACETAG, wxT("USB::IsAvailable() = %s"), m_bAvailable ? "true" : "false");
return m_bAvailable;
}