How to use libusb and libusb_get_device_descriptor()? - c++

I'm learning to use libusb v1.0.0 for the first time on Ubuntu 12.10. Here is some small test code I'm using to try and understand how to use this API:
#include <libusb-1.0/libusb.h>
...
libusb_device **list;
libusb_get_device_list(ctx, &list); // Returns 11 USB devices which is correct.
for (size_t idx = 0; list[idx] != NULL; idx ++)
{
libusb_device *dev = list[idx];
libusb_device_descriptor desc = {0};
int rc = libusb_get_device_descriptor(dev, &desc);
At this point, rc == 0, meaning it should have completed successfully. Source: documentation for *libusb_get_device_descriptor()*.
But the structure desc is always empty. None of the fields ever get set. If I change the last two lines above to this:
libusb_device_descriptor desc = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int rc = libusb_get_device_descriptor(dev, &desc);
...then when libusb_get_device_descriptor() returns, I see desc remains unchanged, confirming for me that I'm not getting what I expect from this API.
I've also tried to run a.out as root just in case this requires elevated privileges. Doing a Google search on libusb_get_device_descriptor hasn't gotten me anywhere.
Relevant commands I ran to try this code:
sudo apt-get install libusb-1.0.0-dev
g++ -ggdb test.cpp -lusb-1.0
./a.out
Ah! Crazy user error! sharth's code helped me figure it out. Here is the code I was actually using -- see if you can spot the error:
std::cout << "rc == " << libusb_get_device_descriptor(dev, &desc) << std::endl
<< "vendor == " << desc.idVendor << std::endl;
I guess the way the compiler evaluates this, it is free to evaluate desc.idVendor before the call to libusb_get_device_descriptor() has actually been made. My bad.

You didn't include a full, compilable test case. So I built one. This works for me on CentOS 6 x64. I'm also running this as a normal user account.
Source
#include <cassert>
#include <cstdio>
#include <libusb-1.0/libusb.h>
int main() {
libusb_context *context = NULL;
libusb_device **list = NULL;
int rc = 0;
ssize_t count = 0;
rc = libusb_init(&context);
assert(rc == 0);
count = libusb_get_device_list(context, &list);
assert(count > 0);
for (size_t idx = 0; idx < count; ++idx) {
libusb_device *device = list[idx];
libusb_device_descriptor desc = {0};
rc = libusb_get_device_descriptor(device, &desc);
assert(rc == 0);
printf("Vendor:Device = %04x:%04x\n", desc.idVendor, desc.idProduct);
}
libusb_free_device_list(list, count);
libusb_exit(context);
}
Output
Vendor:Device = 1d6b:0002
Vendor:Device = 1d6b:0002
Vendor:Device = 8087:0020
Vendor:Device = 8087:0020
Vendor:Device = 0424:2514
Vendor:Device = 10c4:ea60
Vendor:Device = 051d:0002
Vendor:Device = 0624:0248

This is not an standalone answer, it's more a comment to Bill Lynch's post. I'm not able to add a comment to Bill Lynch's post (missing reputation) so I decided to do it this way ;-).
There's a little detail missing in the code above:
you have to free the list you got filled from libusb_get_device_list by hand.
From the libusb docu:
You are expected to unreference all the devices when you are done with them, and then free the list with libusb_free_device_list(). Note that libusb_free_device_list() can unref all the devices for you. Be careful not to unreference a device you are about to open until after you have opened it.

Just to add to Bill's answer, to avoid the multiple warnings you will likely recieve from this line
libusb_device_descriptor desc = {0};
Simply remove the assignment.
libusb_device_descriptor desc;
Not a huge deal, but these things bother me.

Related

Why do none of these methods of sending data over UDP socket show a significant difference in speed/efficiency? FULL MRE AT BOTTOM

I have to send a large amount of data (enough to saturate a gigabit link) out over a UDP socket from an embedded system running (peta)Linux to arbitrary devices. Performance in terms of speed (time spent in socket system calls/copying data esp) and efficiency (CPU time/percentage use) are critical here, so I have been attempting different methods of achieving this, each of which I would expect to be faster according to my research. When I attempt to benchmark this performance, the differences between methods seem to be almost negligible for the most part so I wonder if I am missing anything obvious (like caching playing a part in my benchmark results?) or if I am expecting too much improvement between methods.
Method 1: Copy header and data into buffer, send buffer with sendto().
I had expected this to be the slowest by a margin because of the overhead involved with copying all of the data before each send.
Method 2: Gather buffers with sendmsg() to avoid copying
This is where I expected to see improvements start as copying (in my userspace application at least) had been basically eliminated.
Method 3: Use sendmmsg to avoid overhead of many calls to sendmsg() The man page for this call implies that cutting back on system calls ((~1500 * ~5 * 30)/sec for previous 2 methods) can have performance benefits.
Method 4: Any of the previous + using connect() on the sockets before hand I had seen some suggestions (another) that this could improve performance, again prefaced with a 'maybe':
Connected sockets can save route lookup on each packet by employing a clever optimization — Linux can save a route lookup result on a connection struct. Depending on the specifics of the setup this might save some CPU cycles.
Indeed, this seemed to yield a small benefit on my laptop when writing the MVE, EXCLUSIVELY when using in conjunction with sendmmsg() (25ms average to send 3.5MB 'image' vs ~28.15ms avg ± 0.1ms for all previous methods, including conncet() with sendto() or sendmsg()). This improvement does not seem to have transferred over to the embedded system however (perhaps this connection struct is not impl in that version of the kernel? Something I will look into after posting this, although kernel socket code is not something I pull apart often).
I am hoping anyone can do any of the following:
Answer my main question as to why I do not see much improvement like
I would expect (from eliminating userspace copying and system
call/kernel overhead)
Run the MVE a few ways and let me know if they get similar results/spot any issues
with it
Maybe even point me to a more efficient method compatible with my MVE if
one exists, as I think connect() with sendmmsg() are my best
attempt and I am still not super satisfied. I have seen MSG_ZEROCOPY flag and
options regarding blocking but am not sure if they will make other parts of this more
difficult, and do not want to spend time impl. and testing them before understanding
my current issue
What follows is a 'table' of results from my benchmarking as well as the MVE
sysCall | connected | Time(μS)
sento() | no | 28119
sendmsg() | no | 28340
sendmmsg() | no | 28367
sento() | yes | 28109
sendmsg() | yes | 28341
sendmmsg() | yes | 25021
C++ (I apologize in advance, hacked together from a much larger experiment, but should compile and run with some quick tweaks to inet addrs) I use -O3:
#include <netinet/in.h>
#include <sys/socket.h>
#include <iostream>
#include <chrono>
#include <unistd.h>
#include <string.h>
#include <random>
using namespace std;
void randomize_sim_buf();
uint8_t send_buf[9000], sim_buf[10][1920*1200*3/2], sim_header[20] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
int main(int argc, char const *argv[])
{
int socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in socket_bind, socket_destination;
int return_stat = 0;
uint8_t * p;
iovec iov[2];
msghdr message_hdr;
iovec iovs[1024][2];
mmsghdr mmsg[1024];
socket_bind.sin_family = socket_destination.sin_family = AF_INET;
socket_bind.sin_addr.s_addr = htonl(0x0A42AB01);
socket_destination.sin_addr.s_addr = htonl(0x0A42AB15);
socket_bind.sin_port = htons(0xF3D4);
socket_destination.sin_port = htons(0xF4D4);
return_stat = bind(socket_fd, (sockaddr *)&socket_bind, sizeof(sockaddr_in));
bool connected = false;
cout << "Connect socket?\n";
cin >> connected;
if (connected){
return_stat = connect(socket_fd, (sockaddr *)&socket_destination, sizeof(sockaddr_in));
cout << "Socket connect() returned " << return_stat << endl;
}
string send_type = "";
int packet_size = 1500;
cout << "{sendto|sendmsg|sendmmsg} [packet size]?\n";
cin >> send_type >> packet_size;
uint64_t duration_cnt = 0;
for (int i = 0; i < 1000; i++){
int msg_idx = 0;
auto start = chrono::high_resolution_clock::now();
for (uint j = 0; j < (1920*1200*3/2); j+= packet_size){
uint datalen = (((1920*1200*3/2) - j) >= packet_size) ? packet_size : ((1920*1200*3/2) - j);
p = sim_buf[i % 10];
if (send_type == "sendto"){
memcpy(send_buf, &sim_header, 20);
memcpy(send_buf + 20, &p[j], datalen);
sendto(socket_fd, send_buf, datalen, 0, (sockaddr*)&socket_destination, sizeof(sockaddr_in));
} else if (send_type == "sendmsg"){
iov[0].iov_base = &sim_header;
iov[0].iov_len = 20;
iov[1].iov_base = &p[j];
iov[1].iov_len = datalen;
message_hdr.msg_controllen = 0;
message_hdr.msg_flags = 0;
message_hdr.msg_iov = iov;
message_hdr.msg_iovlen = 2;
message_hdr.msg_name = &socket_destination;
message_hdr.msg_namelen = sizeof(sockaddr_in);
sendmsg(socket_fd, &message_hdr, 0);
} else if (send_type == "sendmmsg"){
iovs[msg_idx][0].iov_base = &sim_header;
iovs[msg_idx][0].iov_len = 20;
iovs[msg_idx][1].iov_base = &p[j];
iovs[msg_idx][1].iov_len = datalen;
mmsg[msg_idx].msg_hdr.msg_controllen = 0;
mmsg[msg_idx].msg_hdr.msg_flags = 0;
mmsg[msg_idx].msg_hdr.msg_name = &socket_destination;
mmsg[msg_idx].msg_hdr.msg_namelen = sizeof(sockaddr_in);
mmsg[msg_idx].msg_hdr.msg_iov = iovs[msg_idx];
mmsg[msg_idx].msg_hdr.msg_iovlen = 2;
msg_idx++;
if (msg_idx == 1024){
sendmmsg(socket_fd, mmsg, msg_idx, 0);
msg_idx = 0;
}
} else {
cout << "Invalid send type supplied\n";
return -1;
}
}
if (send_type == "sendmmsg")
sendmmsg(socket_fd, mmsg, msg_idx, 0);
auto stop = chrono::high_resolution_clock::now();
duration_cnt += std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count();
randomize_sim_buf();
usleep(15000);
}
cout << "Average duration to send a buffer: " << (duration_cnt / 1000) << endl;
return 0;
}
void randomize_sim_buf(){
for (int i = 0; i < 10; i++){
for (int j = 0; j < (1920*1200*3/2); j++){
sim_buf[i][j] = rand() % 255;
}
}
}

Get device name from usb

lsusb command
i want to get device name like on lsusb. I found this code and i tried its all descriptor parameters.Is there any way to get device name like on picture like Log. Opt. Gam. Mouse
#include <stdio.h>
#include <usb.h>
main(){
struct usb_bus *bus;
struct usb_device *dev;
usb_init();
usb_find_busses();
usb_find_devices();
for (bus = usb_busses; bus; bus = bus->next)
for (dev = bus->devices; dev; dev = dev->next){
printf("Trying device %s/%s\n", bus->dirname, dev->filename);
printf("\tID_VENDOR = 0x%04x\n", dev->descriptor.idVendor);
printf("\tID_PRODUCT = 0x%04x\n", dev->descriptor.idProduct);
}
}
the poiter for you is look into libusb library.
starting with libusb_get_device_list which Returns a list of USB devices currently attached to the system.
https://libusb.sourceforge.io/api-1.0/group__libusb__dev.html
you can take it from there.
if you want other way reading /sys/bus/usb/devices directory and read valid devices.
except root hub or other hubs.
EDIT1:
updated link
here is usage
libusb_device **list;
ssize_t cnt = libusb_get_device_list(NULL, &list);
ssize_t i = 0;
if (cnt < 0)
handle_error(); //handle error and return
for (i = 0; i < cnt; i++) {
libusb_device *device = list[i];
// do your work
}
libusb_free_device_list(list, 1);

Linux C++ LibUSB Write Register in USB HUB

In Linux, I have a USB hub with the 'register' shown in the image below. This register is supposed to disable power on a certain port on the hub.
I tried to use LibUSB ( my code is shown below ) to write the register, 0x0A, with all zeros to disable all ports. The problem is, the hub is controlled by the standard Linux USB Hub driver and so the Kernel driver is detached. The write also fails. The failure messages are shown below.
Error messages:
$ /mnt/apps/UsbPowerControl
5 Devices in list.
Vendor:Device = 1908:1320
Vendor:Device = 0403:6001
Vendor:Device = 289d:0010
Vendor:Device = 0424:2513
Vendor:Device = 1d6b:0002
Opening Device = 0424:2513
Device Opened
Kernel Driver Active
Kernel Driver Detached!
Claimed Interface
Data-><-
Writing Data...
libusb: error [submit_bulk_transfer] submiturb failed error -1 errno=2
Write Error
Released Interface
How can I use LibUSB to write this Hub register, to dynamically disable and enable the ports, without unregistering the Linux driver and having my write fail?
#include <iostream>
#include <cassert>
#include <libusb-1.0/libusb.h>
using namespace std;
#define VENDOR_ID 0x0424
#define PRODUCT_ID 0x2513
int main() {
libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices
libusb_device_handle *dev_handle; //a device handle
libusb_context *ctx = NULL; //a libusb session
int r; //for return values
ssize_t cnt; //holding number of devices in list
r = libusb_init(&ctx); //initialize the library for the session we just declared
if(r < 0) {
cout<<"Init Error "<<r<<endl; //there was an error
return 1;
}
libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in the documentation
cnt = libusb_get_device_list(ctx, &devs); //get the list of devices
if(cnt < 0) {
cout<<"Get Device Error"<<endl; //there was an error
return 1;
}
cout<<cnt<<" Devices in list."<<endl;
for (size_t idx = 0; idx < cnt; ++idx) {
libusb_device *device = devs[idx];
libusb_device_descriptor desc = {0};
int rc = libusb_get_device_descriptor(device, &desc);
assert(rc == 0);
printf("Vendor:Device = %04x:%04x\n", desc.idVendor, desc.idProduct);
}
printf("Opening Device = %04x:%04x\n", VENDOR_ID, PRODUCT_ID);
dev_handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID); //these are vendorID and productID I found for my usb device
if(dev_handle == NULL)
cout<<"Cannot open device"<<endl;
else
cout<<"Device Opened"<<endl;
libusb_free_device_list(devs, 1); //free the list, unref the devices in it
unsigned char *data = new unsigned char[1]; //data to write
data[0]=0b00000000;
int actual; //used to find out how many bytes were written
if(libusb_kernel_driver_active(dev_handle, 0) == 1) { //find out if kernel driver is attached
cout<<"Kernel Driver Active"<<endl;
if(libusb_detach_kernel_driver(dev_handle, 0) == 0) //detach it
cout<<"Kernel Driver Detached!"<<endl;
}
r = libusb_claim_interface(dev_handle, 0); //claim interface 0 (the first) of device (mine had jsut 1)
if(r < 0) {
cout<<"Cannot Claim Interface"<<endl;
return 1;
}
cout<<"Claimed Interface"<<endl;
cout<<"Data->"<<data<<"<-"<<endl; //just to see the data we want to write : abcd
cout<<"Writing Data..."<<endl;
r = libusb_bulk_transfer(dev_handle, (0x0A | LIBUSB_ENDPOINT_OUT), data, 1, &actual, 0); //my device's out endpoint was 2, found with trial- the device had 2 endpoints: 2 and 129
if(r == 0 && actual == 1) //we wrote the 1 bytes successfully
cout<<"Writing Successful!"<<endl;
else
cout<<"Write Error"<<endl;
r = libusb_release_interface(dev_handle, 0); //release the claimed interface
if(r!=0) {
cout<<"Cannot Release Interface"<<endl;
return 1;
}
cout<<"Released Interface"<<endl;
libusb_close(dev_handle); //close the device we opened
libusb_exit(ctx); //needs to be called to end the
delete[] data; //delete the allocated memory for data
return 0;
}
int libusb_detach_kernel_driver ( libusb_device_handle * dev,
int interface_number
)
...
If successful, you will then be able to claim the interface and perform I/O.
...
int libusb_kernel_driver_active ( libusb_device_handle * dev,
int interface_number
)
...
If a kernel driver is active, you cannot claim the interface, and libusb will be unable to perform I/O.
...
Due to what is written above, the short answer to the question "How to do I/O without detaching driver" is "You can't".
Why write fails? This is another matter. I'd suggest looking into a number of things:
Check out the value returned from libusb_bulk_transfer, maybe it will give you the idea of what is happening.
Sounds stupid, but I always check it out before anything else: process privileges.
Also, I can suggest another way of approaching the solution, namely sysfs.
I assume that your device(am I right?) supports EEPROM and SMBus access. It means that this support should be manifested in the kernel somewhere around /sys/bus/i2c/devices/[some_device_id]/eeprom (probably another device number, another directory position, etc, because it is all driver-related), but if it can be found and read just as any other file (which is likely, unless something is wrong with the device), then it probably should be able to write into it as well. If the read works, then I suggest to compare the hexdump -C of the found file to the datasheet, and if the data seems legit, try writing directly into your register(file offset).
Anyway, accessing character device files and sysfs files is a general way of accessing drivers' data in linux. Probably you don't even need to use libusb's API to write that single byte.

Send cmd to SD card but error 22 on Linux

I refer an article:
Any way to send commands to SD card from Linux userspace?
and use the source of mmc-util to send cmd to SD card, there is the code:
int cmd_test(int fd, __u8 *ext_csd)
{
int ret = 0;
struct mmc_ioc_cmd idata;
memset(&idata, 0, sizeof(idata));
memset(ext_csd, 0, sizeof(__u8) * 512);
idata.write_flag = 0;
idata.opcode = 17;
idata.arg = 0;
idata.flags = MMC_DATA_READ;
idata.blksz = 512;
idata.blocks = 1;
mmc_ioc_cmd_set_data(idata, ext_csd);
ret = ioctl(fd, MMC_IOC_CMD, &idata);
if (ret)
perror("ioctl");
return ret;
}
finally receive error 22: invalid argument. I try another opcode like 10, 56..., it finally result same error.
The SD card is connected by usb reader, does it cause the error? or there are parameter setting error?
Thanks.

i2c communication in IOKit on Mac OS X

I'm trying to communicate with display over ddc/ci using MacOS X function IOI2CSendRequest.
All works if i just send "set" command, like set brightness. I see that display receive command, because display change brightness.
But when i'm trying to receive reply from display i receive some garbage. What is correct way for send and receive reply with IOI2CSendRequest?
Here is my current code:
memset(&request, 0, sizeof (request));
request.commFlags = 0;
request.sendAddress = addr << 1;
request.sendTransactionType = kIOI2CSimpleTransactionType;
request.sendBuffer = (vm_address_t) package;
request.sendBytes = i;
request.replyAddress = (addr << 1) + 1;
request.replyTransactionType = kIOI2CNoTransactionType;
request.replyBuffer = NULL;
request.replyBytes = 0;
kr = IOI2CSendRequest(Display_, kNilOptions, &request);
mysleep(1000);
memset(&request, 0, sizeof (request));
request.commFlags = 0;
request.sendAddress = addr << 1;
request.sendTransactionType = kIOI2CNoTransactionType;
request.sendBuffer = (vm_address_t)package;
request.sendBytes = 0;
request.replyAddress = (addr << 1) + 1;
request.replyTransactionType = kIOI2CSimpleTransactionType;
request.replyBuffer = (vm_address_t) buf;
request.replyBytes = 127;
memset(buf, 0, request.replyBytes);
kr = IOI2CSendRequest(Display_, kNilOptions, &request);
Both kr and request.result equal to kIOReturnSuccess, but no valid data in buf.
Sent command is "51 82 01 10 AC", where is AC is checksum.
OS is 10.6.8 (Snow Leopard)
Any idea what is wrong in this code?