Files
pip/piusb.cpp

386 lines
12 KiB
C++

#include "piusb.h"
#include "piconfig.h"
#ifdef PIP_USB
# ifdef WINDOWS
# include <lusb0_usb.h>
# else
# include <usb.h>
# endif
#endif
PIUSB::PIUSB(ushort vid, ushort pid): PIIODevice("", ReadWrite, false) {
vid_ = vid;
pid_ = pid;
path_ = PIString::fromNumber(vid_, 16).expandLeftTo(4, "0") + ":" + PIString::fromNumber(pid_, 16).expandLeftTo(4, "0");
dev_num = 1;
intefrace_ = 0;
hdev = 0;
interface_claimed = -1;
timeout_r = timeout_w = 1000;
}
void PIUSB::Endpoint::parse() {
direction = Write;
transfer_type = Control;
synchronisation_type = NoSynchonisation;
usage_type = DataEndpoint;
direction = (Direction)((address >> 7) & 1);
transfer_type = (TransferType)(attributes & 3);
if (transfer_type == Isochronous) {
synchronisation_type = (SynchronisationType)((attributes >> 2) & 3);
usage_type = (UsageType)((attributes >> 4) & 3);
}
}
PIUSB::Endpoint PIUSB::getEndpointByAddress(uchar address) {
piForeachC (Endpoint & i, eps)
if (i.address == address)
return i;
return Endpoint();
}
PIVector<PIUSB::Endpoint> PIUSB::endpointsRead() {
PIVector<Endpoint> ret;
piForeachC (Endpoint & i, eps)
if (i.direction == Endpoint::Read)
ret << i;
return ret;
}
PIVector<PIUSB::Endpoint> PIUSB::endpointsWrite() {
PIVector<Endpoint> ret;
piForeachC (Endpoint & i, eps)
if (i.direction == Endpoint::Write)
ret << i;
return ret;
}
bool PIUSB::setConfiguration(uchar value) {
#ifdef PIP_USB
if (hdev == 0) return false;
bool found = false;
piForeachC (Configuration & c, desc_.configurations)
if (c.value_to_select == value) {found = true; conf_ = c; break;}
if (!found) {
piCoutObj << "Can`t find configuration with \"value_to_select\" =" << value;
return false;
}
if (interface_claimed >= 0)
usb_release_interface(hdev, interface_claimed);
interface_claimed = -1;
return setInterface(conf_.interfaces.front().value_to_select);
#else
return false;
#endif
}
bool PIUSB::setInterface(uchar value) {
#ifdef PIP_USB
if (hdev == 0) return false;
bool found = false;
piForeachC (Interface & i, conf_.interfaces)
if (i.value_to_select == value) {found = true; iface_ = i; break;}
if (!found) {
piCoutObj << "Can`t find interface with \"value_to_select\" =" << value;
return false;
}
if (interface_claimed >= 0)
usb_release_interface(hdev, interface_claimed);
interface_claimed = -1;
if (usb_claim_interface(hdev, iface_.value_to_select) < 0) {
piCoutObj << "Error: Cant`t claim interface!";
return false;
}
eps.clear();
eps = iface_.endpoints;
ep_read = ep_write = Endpoint();
for (int i = 0; i < eps.size_s(); ++i) {
if (eps[i].direction == Endpoint::Read && ep_read.isNull())
ep_read = eps[i];
if (eps[i].direction == Endpoint::Write && ep_write.isNull())
ep_write = eps[i];
}
interface_claimed = value;
return true;
#else
return false;
#endif
}
bool PIUSB::configureDevice(const void * e_main, const void * e_parent) {
#ifdef PIP_USB
PIConfig::Entry * em = (PIConfig::Entry * )e_main;
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
PIString vp = readDeviceSetting<PIString>("device", "", em, ep);
ushort v, p;
if (vp.isEmpty()) {
v = readDeviceSetting<ushort>("vid", vendorID(), em, ep);
p = readDeviceSetting<ushort>("pid", productID(), em, ep);
} else {
v = vp.left(vp.find(":")).toInt(16);
p = vp.right(vp.length() - vp.find(":") - 1).toInt(16);
}
setVendorID(v);
setProductID(p);
setDeviceNumber(readDeviceSetting<int>("deviceNumber", deviceNumber(), em, ep));
setConfiguration(readDeviceSetting<ushort>("configuration", currentConfiguration().value_to_select, em, ep));
setInterface(readDeviceSetting<ushort>("interface", currentInterface().value_to_select, em, ep));
setEndpointRead(Endpoint(readDeviceSetting<ushort>("endpointRead", endpointRead().address, em, ep)));
setEndpointWrite(Endpoint(readDeviceSetting<ushort>("endpointWrite", endpointWrite().address, em, ep)));
return true;
#else
return false;
#endif
}
bool PIUSB::openDevice() {
#ifdef PIP_USB
if (path_.size_s() >= 8) {
vid_ = path_.left(4).toInt(16);
pid_ = path_.right(4).toInt(16);
}
if (hdev != 0) closeDevice();
hdev = 0;
interface_claimed = -1;
ep_write = ep_read = Endpoint();
usb_init();
//usb_set_debug(4);
if (usb_find_busses() < 0) {
piCoutObj << "Error: Cant`t find busses!";
return false;
}
if (usb_find_devices() < 0) {
piCoutObj << "Error: Cant`t find devices!";
return false;
}
//piCoutObj << "Search for device ... " << flush;
int cur_num = 1;
bool found = false;
struct usb_device * dev;
struct usb_bus * bus;
for (bus = usb_get_busses(); bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
if (dev->descriptor.idVendor == vid_ && dev->descriptor.idProduct == pid_) {
if (cur_num == dev_num) {
struct usb_device_descriptor & dd(dev->descriptor);
desc_.usb_spec_number = dd.bcdUSB;
desc_.device_class = dd.bDeviceClass;
desc_.device_subclass = dd.bDeviceSubClass;
desc_.device_protocol = dd.bDeviceProtocol;
desc_.max_packet_size = dd.bMaxPacketSize0;
desc_.id_vendor = dd.idVendor;
desc_.id_product = dd.idProduct;
desc_.id_device_release = dd.bcdDevice;
desc_.index_manufacturer = dd.iManufacturer;
desc_.index_product = dd.iProduct;
desc_.index_serial = dd.iSerialNumber;
desc_.configurations.clear();
for (int c = 0; c < dd.bNumConfigurations; ++c) {
desc_.configurations << Configuration();
Configuration & conf(desc_.configurations.back());
struct usb_config_descriptor & dc(dev->config[c]);
conf.index = c;
conf.value_to_select = dc.bConfigurationValue;
conf.attributes = dc.bmAttributes;
conf.max_power = ushort(dc.MaxPower) * 2;
conf.self_powered = (conf.attributes >> 6) & 1;
conf.remote_wakeup = (conf.attributes >> 5) & 1;
conf.interfaces.clear();
for (int i = 0; i < dc.bNumInterfaces; ++i) {
conf.interfaces << Interface();
Interface & infc(conf.interfaces.back());
struct usb_interface_descriptor * di(dc.interface[c].altsetting);
infc.index = i;
infc.value_to_select = di->bAlternateSetting;
infc.class_code = di->bInterfaceClass;
infc.subclass_code = di->bInterfaceSubClass;
infc.protocol_code = di->bInterfaceProtocol;
infc.endpoints.clear();
for (int e = 0; e < di->bNumEndpoints; ++e) {
infc.endpoints << Endpoint(di->endpoint[e].bEndpointAddress,
di->endpoint[e].bmAttributes,
di->endpoint[e].wMaxPacketSize);
}
}
}
if (!desc_.configurations.isEmpty())
conf_ = desc_.configurations.front();
struct usb_interface_descriptor * is = dev->config->interface->altsetting;
int epn = is->bNumEndpoints;
eps.clear();
for (int i = 0; i < epn; ++i) {
eps << Endpoint(is->endpoint[i].bEndpointAddress,
is->endpoint[i].bmAttributes,
is->endpoint[i].wMaxPacketSize);
if (eps.back().direction == Endpoint::Write && (eps.back().address == ep_write.address || ep_write.address == 0)) ep_write = eps.back();
if (eps.back().direction == Endpoint::Read && (eps.back().address == ep_read.address || ep_read.address == 0)) ep_read = eps.back();
}
//piCoutObj << "Device found at address:" << "Bus: " << dev->bus->dirname << ", Device: " << dev->filename;
found = true;
break;
} else cur_num++;
}
}
if (found) break;
}
if (!found) {
piCoutObj << "Error: Cant`t find device!";
return false;
}
//piCoutObj << "Open ... " << flush;
hdev = usb_open(dev);
if (hdev == 0) {
piCoutObj << "Error: Cant`t open device:" << usb_strerror();
return false;
}// else piCoutObj << "ok";
//usb_reset(hdev);
//usb_set_configuration(hdev, 1);
//usb_set_altinterface(hdev, 0);
# ifndef WINDOWS
char tbuff[256];
//piCoutObj << "Check for bounded driver ... " << flush;
if (usb_get_driver_np(hdev, intefrace_, tbuff, sizeof(tbuff) - 1) >= 0) {
//piCoutObj << "yes" << "Found driver: " << tbuff;
//piCoutObj << "Detach driver ... " << flush;
if (usb_detach_kernel_driver_np(hdev, intefrace_)< 0) {
piCoutObj << "Error: Cant`t detach bounded driver!";
return false;
}// else piCoutObj << "ok";
}// else piCoutObj << "no";
# endif
//piCoutObj << "Claim interface ... " << flush;
if (usb_claim_interface(hdev, intefrace_) < 0) {
piCoutObj << "Error: Cant`t claim interface:" << usb_strerror();
return false;
} // else piCoutObj << "ok";
interface_claimed = intefrace_;
return true;
#else
return false;
#endif
}
bool PIUSB::closeDevice() {
#ifdef PIP_USB
if (hdev == 0) return true;
//usb_reset(hdev);
usb_release_interface(hdev, intefrace_);
usb_close(hdev);
hdev = 0;
interface_claimed = -1;
return true;
#else
return false;
#endif
}
int PIUSB::read(void * read_to, int max_size) {
#ifdef PIP_USB
if (!opened_ || ep_read.isNull()) return -1;
switch (ep_read.transfer_type) {
case Endpoint::Bulk: /*piCoutObj << "bulk read" << max_size;*/ return usb_bulk_read(hdev, ep_read.address, (char * )read_to, max_size, timeout_r); break;
case Endpoint::Interrupt: return usb_interrupt_read(hdev, ep_read.address, (char * )read_to, max_size, timeout_r); break;
default: break;
}
return -1;
#else
return -1;
#endif
}
int PIUSB::write(const void * data, int max_size) {
#ifdef PIP_USB
if (!opened_ || ep_write.isNull()) return -1;
switch (ep_read.transfer_type) {
case Endpoint::Bulk: /*piCoutObj << "bulk write" << max_size;*/ return usb_bulk_write(hdev, ep_write.address, (char * )const_cast<void * >(data), max_size, timeout_w); break;
case Endpoint::Interrupt: return usb_interrupt_write(hdev, ep_read.address, (char * )data, max_size, timeout_w); break;
default: break;
}
return -1;
#else
return -1;
#endif
}
int PIUSB::controlWrite(const void * data, int max_size) {
#ifdef PIP_USB
if (!opened_) return -1;
//return usb_control_msg(hdev, );
return -1;
#else
return -1;
#endif
}
void PIUSB::flush() {
#ifdef PIP_USB
if (!opened_) return;
if (!ep_read.isNull()) usb_resetep(hdev, ep_read.address);
if (!ep_write.isNull()) usb_resetep(hdev, ep_write.address);
#endif
}
PICout operator<<(PICout s, const PIUSB::Endpoint & v) {
s.setControl(0, true);
s << NewLine << "{" << NewLine;
if (v.isNull())
s << " " << "Null Endpoint";
else {
s << " " << "Address: " << v.address << NewLine;
s << " " << "Attributes: " << v.attributes << NewLine;
s << " " << "Direction: " << (v.direction == PIUSB::Endpoint::Write ? "Write" : "Read") << NewLine;
s << " " << "Transfer Type: ";
switch (v.transfer_type) {
case PIUSB::Endpoint::Control: s << "Control" << NewLine; break;
case PIUSB::Endpoint::Bulk: s << "Bulk" << NewLine; break;
case PIUSB::Endpoint::Interrupt: s << "Interrupt" << NewLine; break;
case PIUSB::Endpoint::Isochronous: s << "Isochronous" << NewLine; break;
default: break;
}
if (v.transfer_type == PIUSB::Endpoint::Isochronous) {
s << " " << "Synchronisation Type: ";
switch (v.synchronisation_type) {
case PIUSB::Endpoint::NoSynchonisation: s << "No Synchonisation" << NewLine; break;
case PIUSB::Endpoint::Asynchronous: s << "Asynchronous" << NewLine; break;
case PIUSB::Endpoint::Adaptive: s << "Adaptive" << NewLine; break;
case PIUSB::Endpoint::Synchronous: s << "Synchronous" << NewLine; break;
default: break;
}
s << " " << "Usage Type: ";
switch (v.usage_type) {
case PIUSB::Endpoint::DataEndpoint: s << "Data Endpoint" << NewLine; break;
case PIUSB::Endpoint::FeedbackEndpoint: s << "Feedback Endpoint" << NewLine; break;
case PIUSB::Endpoint::ExplicitFeedbackDataEndpoint: s << "Explicit Feedback Data Endpoint" << NewLine; break;
default: break;
}
}
s << " " << "Max Packet Size: " << v.max_packet_size << NewLine;
}
s << "}" << NewLine;
s.restoreControl();
return s;
}