Usb mouse driver using LIBUSB - c++

I want to try "userspace" driver(it isn't my code) on Ubuntu. And I have this code:
#include <stdio.h>
#include <string.h>
#include <usb.h>
#include <usbpp.h>
#define DEBUG_LEVEL 0
struct usb_bus *busses,*bus,*dbus;
int main(int argc, char *argv[])
{
struct usb_device *dev;
char *buf;
int n,x,r, ret;
char *ibus, *idev;
char string[64];
int found = 0;
usb_dev_handle *udev;
usb_set_debug(DEBUG_LEVEL);
usb_init(); //initilize the usb library
usb_find_busses();
usb_find_devices();
busses=usb_get_busses();
//use the command line arguments for Bus and Device
if (argc >= 3) {
ibus = argv[1];
idev = argv[2];
}
else { printf("Usage: usbtest <Bus> <Device> [<numBytes>])\n"); exit(1); }
printf("Bus = %s Device = %s\n", ibus, idev);
for (bus=busses; bus && (found == 0); bus=bus->next) { // busses loop
if (strcmp(bus->dirname, ibus) == 0) {
for (dev=bus->devices; dev; dev=dev->next) { // devices loop
if (strcmp(dev->filename, idev) == 0) { dbus=bus; found=1; break; }
}
}
}
if (found == 0) { printf("Unable to find the required device !\nexiting\n"); exit(1); }
printf("Found device\n");
printf("Now we are dealing with device from vendor ID : %d (%x) \n",dev->descriptor.idVendor,dev->descriptor.idVendor);
printf("Trying to open the device...\n");
if (udev=usb_open(dev)) printf("Device opened successfully.\n");
else { printf("Operation failed :-("); exit(1);}
buf=(char*)calloc(1,100);
if (usb_get_driver_np(udev,0,buf,100)) printf("Could not read the driver name :-( %s\n",buf);
else printf("Kernel Using Driver :\n");
// detach the driver from the kernel , seems to be just like rmmod?
if (usb_detach_kernel_driver_np(udev,0)) printf("Error detaching the device :-(\n");
else printf("Device detached successfully from the kernel.\n");
// reserving the device interface for our application, if another driver/software
//is using the device , it will return 'interface busy'
if (r=usb_claim_interface(udev,0)) printf("Interface Claimed !!\n");
printf("Interface Claim Status : %d\n",r);
printf("Device Protocol : %d\n",dev->descriptor.bDeviceProtocol);
printf("Report Length : %d\n",dev->descriptor.bLength);
printf("Decriptor Type : %d\n",dev->descriptor.bDescriptorType);
printf("End Points : %d\n",dev->config->interface->altsetting->bNumEndpoints);
printf("Interface Class : %d\n",dev->config->interface->altsetting->bInterfaceClass);
printf("Protocol : %d\n",dev->config->interface->altsetting->bInterfaceProtocol);
printf("Interface Number: %d\n",dev->config->interface->altsetting->bInterfaceNumber);
printf("Device Filename : %s\n",dev->filename);
printf("Bus Dir Name : %s\n",dbus->dirname);
usb_get_string_simple(udev,dev->descriptor.iManufacturer,string,sizeof(string));
printf("Device Manfucaturer : %s\n",string);
usb_get_string_simple(udev,dev->descriptor.iProduct,string,sizeof(string));
printf("Product Name : %s\n",string);
usb_get_string_simple(udev,dev->descriptor.iSerialNumber,string,sizeof(string));
printf("Device Serial Number: %s\n",string);
printf("End point addresses : 0x%x\n",dev->config->interface->altsetting->endpoint->bEndpointAddress);
int numBytes = 4;
int errCount = 0;
unsigned char endPoint = 0x81;
int i;
int tmp1 = 5;
int tmp2 = 5;
// reset usb device if command line numBytes = 0 and exit
if (argc == 4 && atoi(argv[3]) == 0) { usb_reset(udev); exit(0); }
// use command line value for numBytes if supplied
if (argc == 4) numBytes = atoi(argv[3]);
if (numBytes > 64) numBytes = 64;
while (1) {
for (x=0; x<numBytes; x++) string[x]=0;
// read numBytes bytes using interrupt_read,
r = usb_interrupt_read(udev, endPoint, string, numBytes, 0);
system("clear");
tmp1+=string[1];
tmp2+=string[2];
if (tmp1>=0 && tmp2>=0 && tmp1<=150 && tmp2<=50){
for (i=0;i<tmp2;i++) printf("\n");
for (i=0;i<tmp1;i++) printf(".");
if (string[0]==0) printf ("X");
else if (string[0]==1) printf("L");
else if(string[0]==2) printf("R");
else if(string[0]==3) printf("LR");
else if(string[0]==4) printf("M");
}
else {
if(tmp1<0) tmp1=0;
else if (tmp1>150) tmp1=150;
if (tmp2<0) tmp2=0;
else if (tmp2>50) tmp2=50;
}
if (string[3]==1) printf ("\nSCROLL UP");
if (string[3]==-1) printf ("\nSCROLL DOWN");
printf ("\n(%d, %d)",tmp1,tmp2);
if ( r < 0 ) errCount++;
if (errCount >= 100) break;
usb_clear_halt(udev,endPoint);
}
printf("Closing Device.\n");
usb_release_interface(udev,0);
usb_close(udev);
return EXIT_SUCCESS;
}
In this code are using API from libusb-0.1 - but i don't know excact version of it. Probably - it is libusb-0.1.12 (it have both headers "usb.h" and "usbpp.h", which are using in this code). I have download this version on ubuntu, install it, using
./configure && make && make install && sudo ldconfig
And after that I tried to do
gcc -c mouse.c -w
to compile this code. Bit it doesnt compile. It has different errors in "usbpp.h" (in standart includes like "string" or "list") or smth else..
Can anyone tell me, what i'n doing fundamentally wrong? And how can i try this code?
PS - i try do test this code on ubuntu 9.04 and ubuntu 12>, both as virtual machines. It's my task in university.

usbpp.h is a c++ header file but you run gcc which is a c compiler. Run g++ instead.

I found one another way to solve this problem:
gcc -o mouse ./mouse.cpp -lstdc++ -lusb

Related

How can I get the NumLock state in C++ in a platform independent way? I am primarily having problems with the Unix side

I am trying to get the state of the NumLock key in a platform independent fashion in a C/C++ application. I can get the status using GetKeyState and #defines for the Windows code, but I am having problems with the Unix code (see below).
The code fails with an "Invalid Argument", err code 22 - but I do not understand why. I have tried various different ioctl requests (KDGETLED, KDGKBLED, KDGKBMETA) without success and have run out of ideas.
BTW the only reason for it being two functions was that I was struggling to open the "/dev/..." file and trying different files! This is now fixed (by adding the user to the "input" group - but ideally I would like to avoid this necessity).
#defined (_WIN32)
// Code here works ok
#else
#include <sys/ioctl.h>
#include <sys/kd.h>
#include <sys/vt.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <sstream>
int fdKeybd;
int tryStrForInput(std::string &inStr, int *pNumLed)
{
int testVal = -1;
std::string kybdStr = inStr;
printf("\nTry: %s", kybdStr.c_str());
fdKeybd = open(kybdStr.c_str(), O_RDONLY | O_NONBLOCK);
if ( fdKeybd < 0 ) {
printf(" Opening file : Failed. ");
printf ("Error no is : %d ", errno);
printf("Error description is : %s",strerror(errno));
} else {
testVal = ioctl(fdKeybd, KDGKBMETA, pNumLed);
if(testVal != -1) printf(" Success");
else {
printf(" Getting NumLock : Failed. ");
printf ("Error no is : %d ", errno);
printf("Error description is : %s",strerror(errno));
}
}
return testVal;
}
bool isNumlockActivated(void)
{
int NUM_LED = 0x00;
bool bNumLockOn = false;
int testVal = -1;
std::string kybdStr = "/dev/input/by-path/platform-i8042-serio-0-event-kbd";
testVal = tryStrForInput(kybdStr, &NUM_LED);
if(testVal != -1) {
if((NUM_LED == 0x02) || (NUM_LED == 0x03) || (NUM_LED == 0x06) || (NUM_LED == 0x07)) {
bNumLockOn = true;
}
}
close(fdKeybd);
return bNumLockOn;
}
#endif
After much stumbling about in the dark I found the following code works for the Linux side. The reason being I was trying to get the wrong file descriptor (all I actually needed was the standard input) and hence why it did not work.
This posted in case it helps anyone else.
bool isNumlockActivated(void)
{
int fdKeybd = STDIN_FILENO; // Normally 0
int NUM_LED = 0x00;
bool bNumLockOn = false;
int testVal = ioctl(fdKeybd, KDGKBLED, &NUM_LED);
if(testVal == -1) {
printf(" Getting NumLock : Failed. ");
printf ("Error no is : %d ", errno);
printf("Error description is : %s",strerror(errno));
} else {
if((NUM_LED == 0x02) || (NUM_LED == 0x03) || (NUM_LED == 0x06) || (NUM_LED == 0x07)) {
bNumLockOn = true;
}
}
return bNumLockOn;
}
However please note that this is only picking up on the numLock LED state. So if ioctl has been used to control the numLock LED you would have to find the correct key state instead - probably by using a different ioctl request (look at: https://www.tutorialspoint.com/unix_system_calls/ioctl_list.htm)

Linux - Shell does not redirect outputs

I created a simple shell in Linux using fork() and execvp(). It works fine with cat, ls etc. but when I try to redirect its output like ./hello.o > output.txt it doesn't work.
I am guessing I didn't provide the write path to look for the definitions. My shell is currently searching on /bin/ path where most of the commands are stored.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define ARG_SIZE 100 // MAX LENGTH FOR ARGUMENTS
#define PATH "/bin/" // PATH FOR ARGUMENTS
int main() {
char inputLine[BUFSIZ];
char *argv[ARG_SIZE];
// for path + argv
char programPath[200];
while (1) {
printf("myshell> ");
// check if ctrl + D is pressed
if (fgets(inputLine, BUFSIZ, stdin) == NULL)
break;
inputLine[strlen(inputLine) - 1] = '\0';
// check if exit is typed
if (strcmp(inputLine, "exit") == 0)
break;
int i = 0;
argv[0] = strtok(inputLine, " \n");
for (i = 0; argv[i] && i < ARG_SIZE-1; ++i)
argv[++i] = strtok(NULL, " \n");
// create a fork call
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
// parent
if (pid != 0) {
wait();
// child
} else {
strcat(programPath, argv[0]);
// will not return unless it fails
execvp(programPath, argv);
perror("execvp");
exit(1);
}
}
return 0;
}

Dtrace from C does not yield same profiling result compared to command line

I want to programmatically trace stacks from C for Node.js (JS addresses aside).
The following command gives me stacks with resolved c++ symbols.
sudo dtrace -C -n 'profile-101 /pid == 13221/ { ustack() }'
The following C code only returns addresses for Node's C/C++ code. What would be the equivalent?
#include <dtrace.h>
#include <signal.h>
#include <stdio.h>
struct ps_prochandle *g_pr;
static dtrace_hdl_t* g_dtp;
static int chewrec (const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg) {
// A NULL rec indicates that we've processed the last record.
if (rec == NULL) {
return (DTRACE_CONSUME_NEXT);
}
return (DTRACE_CONSUME_THIS);
}
static const char* g_prog =
"#pragma D option switchrate=1000hz\n"
"profile-1ms /pid == 13221/ {\n"
"ustack();\n"
"}";
static int g_intr;
static int g_exited;
static void intr (int signo) {
g_intr = 1;
}
int main (int argc, char** argv) {
int err;
if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
fprintf(stderr, "failed to initialize dtrace: %s\n", dtrace_errmsg(NULL, err));
return -1;
}
printf("Dtrace initialized\n");
(void) dtrace_setopt(g_dtp, "bufsize", "4m");
(void) dtrace_setopt(g_dtp, "aggsize", "4m");
printf("dtrace options set\n");
dtrace_prog_t* prog;
if ((prog = dtrace_program_strcompile(g_dtp, g_prog, DTRACE_PROBESPEC_NAME, DTRACE_C_CPP, 0, NULL)) == NULL) {
fprintf(stderr, "failed to compile dtrace program\n");
return -1;
} else {
printf("dtrace program compiled\n");
}
dtrace_proginfo_t info;
if (dtrace_program_exec(g_dtp, prog, &info) == -1) {
fprintf(stderr, "failed to enable dtrace probes\n");
return -1;
} else {
printf("dtrace probes enabled\n");
}
struct sigaction act;
(void) sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = intr;
(void) sigaction(SIGINT, &act, NULL);
(void) sigaction(SIGTERM, &act, NULL);
if (dtrace_go(g_dtp) != 0) {
fprintf(stderr, "could not start instrumentation\n");
return -1;
} else {
printf("instrumentation started ..\n");
}
int done = 0;
do {
if (!g_intr && !done) {
dtrace_sleep(g_dtp);
}
if (done || g_intr || g_exited) {
done = 1;
if (dtrace_stop(g_dtp) == -1) {
fprintf(stderr, "could not stop tracing\n");
return -1;
}
}
switch (dtrace_work(g_dtp, stdout, NULL, chewrec, NULL)) {
case DTRACE_WORKSTATUS_DONE:
done = 1;
break;
case DTRACE_WORKSTATUS_OKAY:
break;
default:
fprintf(stderr, "processing aborted");
return -1;
}
} while (!done);
printf("closing dtrace\n");
dtrace_close(g_dtp);
return 0;
}
From the dtrace-Mailing list, Robert Mustacchi:
TL;DR resolve symbols yourself in userland.
"So, all the symbol resolution processing is always done in user land. In
other words, DTrace in the kernel only ever gathers addresses like
you're seeing for the cases where you're using ustack and not a ustack
handler via the jstack() action (jstack() also only returns symbols for
non-native frames). Note that if you want to see the JavaScript specific
symbols in addition to the native ones, you'll want to be using jstack()
in your examples and not ustack().
The way that these you can perform these mappings will change depending
on what system you're on. If you look at what DTrace does on illumos for
printing the results of ustack()
(http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libdtrace/common/dt_consume.c#1320),
then you'll see that it uses libproc and the Plookup_by_addr() function
to perform the translation. Though it's worth pointing out that neither
are stable interfaces, though they seldom change."

Get process creation date-time in OSX with C / C++

Given a process id, what is the best way to find the process's creation date-time using C/C++ ?
I'd suggest looking at the top and ps source code (in particular, libtop.c).
I think the following call should be what you need:
int proc_pidbsdinfo(proc_t p, struct proc_bsdinfo *pbsd, int zombie);
From <sys/proc_info.h>:
struct proc_bsdinfo {
...
struct timeval pbi_start;
...
}
Unfortunately there is no public interface for process inspection so the calls are not only version-dependant but also likely to change in future releases.
Here is a simple utility demonstrating how to do this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/errno.h>
#include <sys/sysctl.h>
int main(int argc, char **argv) {
// Check arguments
if (argc != 2) {
fprintf(stderr,"usage: %s PID\n", argv[0]);
return 1;
}
// Parse and validate PID argument
errno = 0;
char *end = NULL;
long pid = strtol(argv[1], &end, 10);
if (errno != 0 || end == argv[1] || end == NULL || *end != 0 || ((pid_t)pid) != pid) {
fprintf(stderr,"%s: bad PID argument: %s\n", argv[0], argv[1]);
return 1;
}
// Get process info from kernel
struct kinfo_proc info;
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid };
size_t len = sizeof info;
memset(&info,0,len);
int rc = sysctl(mib, (sizeof(mib)/sizeof(int)), &info, &len, NULL, 0);
if (rc != 0) {
fprintf(stderr,"%s: sysctl failed with errno=%d\n", argv[0], errno);
return 1;
}
// Extract start time and confirm process exists
struct timeval tv = info.kp_proc.p_starttime;
if (tv.tv_sec == 0) {
fprintf(stderr,"%s: no such PID %d\n", argv[0], (int)pid);
return 1;
}
// Convert to string - no \n because ctime() result is already \n-terminated
printf("PID %d started at %s", (int)pid, ctime(&(tv.tv_sec)));
return 0;
}
Compile it: clang -o procstart procstart.c
Example of running it:
$ ./procstart $$
PID 37675 started at Sat Apr 9 20:01:55 2022
Note the sysctl API this is calling is undocumented and as such (at least in theory) subject to change at any time. In practice however, it has been rather stable across releases, so while nobody can predict what Apple might do in the future, I think the risk of them breaking this is low.

Open a device by name using libftdi or libusb

I am using libftdi with multiple ftdi devices for a program running on Ubuntu 14.04. I have a udev rule that detects the devices based on a custom manufacturer string and gives them a symlink in the dev directory. It would look similar to /dev/my-device. I would like to use libftdi to open the device using this string instead of the pid/vid/serial number.
I did not see that this capability was available in libftdi so I checked libusb and didn't see that functionality either.
You could try this:
static int usbGetDescriptorString(usb_dev_handle *dev, int index, int langid, char *buf, int buflen) {
char buffer[256];
int rval, i;
// make standard request GET_DESCRIPTOR, type string and given index
// (e.g. dev->iProduct)
rval = usb_control_msg(dev,
USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid,
buffer, sizeof(buffer), 1000);
if (rval < 0) // error
return rval;
// rval should be bytes read, but buffer[0] contains the actual response size
if ((unsigned char)buffer[0] < rval)
rval = (unsigned char)buffer[0]; // string is shorter than bytes read
if (buffer[1] != USB_DT_STRING) // second byte is the data type
return 0; // invalid return type
// we're dealing with UTF-16LE here so actual chars is half of rval,
// and index 0 doesn't count
rval /= 2;
/* lossy conversion to ISO Latin1 */
for (i = 1; i < rval && i < buflen; i++) {
if (buffer[2 * i + 1] == 0)
buf[i - 1] = buffer[2 * i];
else
buf[i - 1] = '?'; /* outside of ISO Latin1 range */
}
buf[i - 1] = 0;
return i - 1;
}
static usb_dev_handle * usbOpenDevice(int vendor, char *vendorName, int product, char *productName) {
struct usb_bus *bus;
struct usb_device *dev;
char devVendor[256], devProduct[256];
usb_dev_handle * handle = NULL;
usb_init();
usb_find_busses();
usb_find_devices();
for (bus = usb_get_busses(); bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
if (dev->descriptor.idVendor != vendor ||
dev->descriptor.idProduct != product)
continue;
/* we need to open the device in order to query strings */
if (!(handle = usb_open(dev))) {
fprintf(stderr, "Warning: cannot open USB device: %sn",
usb_strerror());
continue;
}
/* get vendor name */
if (usbGetDescriptorString(handle, dev->descriptor.iManufacturer, 0x0409, devVendor, sizeof(devVendor)) < 0) {
fprintf(stderr,
"Warning: cannot query manufacturer for device: %sn",
usb_strerror());
usb_close(handle);
continue;
}
/* get product name */
if (usbGetDescriptorString(handle, dev->descriptor.iProduct, 0x0409, devProduct, sizeof(devVendor)) < 0) {
fprintf(stderr,
"Warning: cannot query product for device: %sn",
usb_strerror());
usb_close(handle);
continue;
}
if (strcmp(devVendor, vendorName) == 0 &&
strcmp(devProduct, productName) == 0)
return handle;
else
usb_close(handle);
}
}
return NULL;
}