Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing USB file descriptor to Android NDK program

I am trying to port some software written in C to the Android platform. This software has a component that reads and writes from and to a connected USB device. What I am trying to do is open up a connection to the device in Java, then pass the file descriptor for the USB device(s) to the JNI code.

Below is the (relevant) output of lsof for my app which shows I have two descriptors for the USB device:

com.tim    8861     u0_a66   35       ???                ???       ???        ??? /dev/bus/usb/001/002
com.tim    8861     u0_a66   36       ???                ???       ???        ??? socket:[51170]
com.tim    8861     u0_a66   37       ???                ???       ???        ??? socket:[51173]
com.tim    8861     u0_a66   38       ???                ???       ???        ??? /dev/bus/usb/001/003

I've passed both descriptors (above as 35 and 38) to my native method, but when I try and write to either of the file descriptors, write() returns -1, and I get an EINVAL error.

Here is the body of my native method:

char buff[1024] = {0};
jsize len = (*env)->GetArrayLength(env, fds);
jint *arr = (*env)->GetIntArrayElements(env, fds, 0);
int i;

char data[4] = {
    0x09,
    0x90,
    0x50,
    0x50,
};

for (i = 0; i < len; i++) {
    int wrote = write(arr[i], data, 4);

    int flags = fcntl(arr[i], F_GETFL);
    char *err = strerror(errno);
    sprintf(buff, "%sFD: %d  \n"
    "wrote: %d  \n"
    "(err: %d %s)  \n"
    "flags: %d  \n"
    "NBIO %d  \n"
    "readonly %d  \n"
    "writeonly %d  \n"
    "both %d  \n"
    "append %d  \n"
    "large file %d  \n\n", buff, arr[i], wrote, errno, err, flags, flags & O_NONBLOCK,
        flags & O_RDONLY, flags & O_WRONLY, flags & O_RDWR, flags & O_APPEND,
        flags & O_LARGEFILE);
}
return (*env)->NewStringUTF(env, buff);

The string that is returned when invoking that method is:

FD: 35  
wrote: -1  
(err: 22 Invalid argument)  
flags: 32770  
NBIO 0  
readonly 0  
writeonly 0  
both 2  
append 0  
large file 32768  

FD: 38  
wrote: -1  
(err: 22 Invalid argument)  
flags: 32770  
NBIO 0  
readonly 0  
writeonly 0  
both 2  
append 0  
large file 32768

Writing to the USB device does work through Java, so it appears to just be an issue when trying to do it via native code.

Does anyone have any experience doing something like this?

like image 737
Tim Cooper Avatar asked Feb 17 '23 08:02

Tim Cooper


1 Answers

It seems that using write() on a USB file descriptor doesn't exactly work, since there are multiple endpoints on the USB device where the data could be written.

I was able use the ioctl() function to perform a bulk transfer to a particular endpoint on the device:

#include <linux/usbdevice_fs.h>
#include <sys/ioctl.h>

// ...

char data[4] = {0x09, 0x90, 0x50, 0x50};

struct usbdevfs_bulktransfer bt;
bt.ep = usb_endpoint;  /* endpoint (received from Java) */
bt.len = 4;            /* length of data */
bt.timeout = 100;      /* timeout in ms */
bt.data = data;        /* the data */

int rtn = ioctl(fd, USBDEVFS_BULK, &bt);
like image 194
Tim Cooper Avatar answered Feb 27 '23 02:02

Tim Cooper