ioctl returns ENOENT 试图 post 对 Isoc 设备端点的 URB 请求(从 android 的 JNI 访问)
ioctl returns ENOENT trying to post URB request to Isoc device endpoint (accessed from android's JNI)
看来我在 Android/JNI 中缺少一些香料...
我正在尝试访问自定义复合 USB 设备,通过 OTG USB 连接到常规(未 root)Android 设备。设备公开了几个接口,其中包括音频流和 CDC 终端,枚举正常,音频在 OS 使用时播放。
当我尝试从我的应用程序访问此设备时,使用 CDC 完全没有问题。我可以在 SDK 的上下文中成功声明接口并从在 JNI 环境中启动的单独线程访问其端点。
char read_buf[64];
struct usbdevfs_bulktransfer ctrl;
memset(&ctrl, 0, sizeof(ctrl));
int fd = ((thread_arg_t*)arg)->fd;
ctrl.ep = ((thread_arg_t*)arg)->ep_in;
ctrl.len = sizeof(read_buf);
ctrl.data = read_buf;
ctrl.timeout = 0;
...
int ret = ioctl(fd, USBDEVFS_BULK, &ctrl);
因此,它可以很好地读取来自 USB 设备的 CDC 部分的数据...
但是当涉及到音频接口时,肯定出了问题...我可以声明对接口的独占访问权限,公开其 Isoc 端点,它 returns 是的,但是当我尝试流式传输音频数据时通过我单独线程的适当端点,ioctl returns ENOENT error in errno:
int fd = ((thread_arg_t*)arg)->fd;
struct usbdevfs_urb *urb = (struct usbdevfs_urb*)malloc(sizeof(struct usbdevfs_urb) + sizeof(struct usbdevfs_iso_packet_desc));
memset(urb, 0, sizeof(struct usbdevfs_urb) + sizeof(struct usbdevfs_iso_packet_desc));
uint8_t empty_buffer[192] = {0};
urb->type = USBDEVFS_URB_TYPE_ISO;
urb->endpoint = ((thread_arg_t*)arg)->ep_out;
urb->status = -1;
urb->flags = USBDEVFS_URB_ISO_ASAP;
urb->buffer = empty_buffer;
urb->buffer_length = 192;
urb->actual_length = 0;
urb->start_frame = 0;
urb->number_of_packets = 1;
urb->error_count = 0;
urb->signr = 0;
urb->usercontext = empty_buffer
struct usbdevfs_iso_packet_desc *iso_desc = &urb->iso_frame_desc[0];
iso_desc->length = 192;
iso_desc->actual_length = 0;
iso_desc->status = -1;
.....
int ret = ioctl(fd, USBDEVFS_SUBMITURB, urb);
有什么线索吗?
几个小时的调试结果并不理想...问题出在 Android 的 API 中。当你声明接口时,要求 Android 强制断开绑定的驱动程序,它只会在某些特定情况下断开驱动程序与你的接口的连接......(根据消息来源)。如果没有,您将无法独占使用界面。我可以采用的唯一解决方案是显式调用 ioctl():
usbdevfs_ioctl command;
command.ifno = 0;
command.ioctl_code = USBDEVFS_DISCONNECT;
command.data = NULL;
ioctl(fd, USBDEVFS_IOCTL, &command );
command.ifno = 1;
command.ioctl_code = USBDEVFS_DISCONNECT;
command.data = NULL;
ioctl(fd, USBDEVFS_IOCTL, &command );
然后确实有必要切换界面 altsetting
struct usbdevfs_setinterface setif;
setif.altsetting = 1;
setif.interface = 1;
ioctl(fd, USBDEVFS_SETINTERFACE, &setif);
否则,端点将像初始时一样不可用 post(至少在我的 USB 设备中)
看来我在 Android/JNI 中缺少一些香料...
我正在尝试访问自定义复合 USB 设备,通过 OTG USB 连接到常规(未 root)Android 设备。设备公开了几个接口,其中包括音频流和 CDC 终端,枚举正常,音频在 OS 使用时播放。
当我尝试从我的应用程序访问此设备时,使用 CDC 完全没有问题。我可以在 SDK 的上下文中成功声明接口并从在 JNI 环境中启动的单独线程访问其端点。
char read_buf[64];
struct usbdevfs_bulktransfer ctrl;
memset(&ctrl, 0, sizeof(ctrl));
int fd = ((thread_arg_t*)arg)->fd;
ctrl.ep = ((thread_arg_t*)arg)->ep_in;
ctrl.len = sizeof(read_buf);
ctrl.data = read_buf;
ctrl.timeout = 0;
...
int ret = ioctl(fd, USBDEVFS_BULK, &ctrl);
因此,它可以很好地读取来自 USB 设备的 CDC 部分的数据...
但是当涉及到音频接口时,肯定出了问题...我可以声明对接口的独占访问权限,公开其 Isoc 端点,它 returns 是的,但是当我尝试流式传输音频数据时通过我单独线程的适当端点,ioctl returns ENOENT error in errno:
int fd = ((thread_arg_t*)arg)->fd;
struct usbdevfs_urb *urb = (struct usbdevfs_urb*)malloc(sizeof(struct usbdevfs_urb) + sizeof(struct usbdevfs_iso_packet_desc));
memset(urb, 0, sizeof(struct usbdevfs_urb) + sizeof(struct usbdevfs_iso_packet_desc));
uint8_t empty_buffer[192] = {0};
urb->type = USBDEVFS_URB_TYPE_ISO;
urb->endpoint = ((thread_arg_t*)arg)->ep_out;
urb->status = -1;
urb->flags = USBDEVFS_URB_ISO_ASAP;
urb->buffer = empty_buffer;
urb->buffer_length = 192;
urb->actual_length = 0;
urb->start_frame = 0;
urb->number_of_packets = 1;
urb->error_count = 0;
urb->signr = 0;
urb->usercontext = empty_buffer
struct usbdevfs_iso_packet_desc *iso_desc = &urb->iso_frame_desc[0];
iso_desc->length = 192;
iso_desc->actual_length = 0;
iso_desc->status = -1;
.....
int ret = ioctl(fd, USBDEVFS_SUBMITURB, urb);
有什么线索吗?
几个小时的调试结果并不理想...问题出在 Android 的 API 中。当你声明接口时,要求 Android 强制断开绑定的驱动程序,它只会在某些特定情况下断开驱动程序与你的接口的连接......(根据消息来源)。如果没有,您将无法独占使用界面。我可以采用的唯一解决方案是显式调用 ioctl():
usbdevfs_ioctl command;
command.ifno = 0;
command.ioctl_code = USBDEVFS_DISCONNECT;
command.data = NULL;
ioctl(fd, USBDEVFS_IOCTL, &command );
command.ifno = 1;
command.ioctl_code = USBDEVFS_DISCONNECT;
command.data = NULL;
ioctl(fd, USBDEVFS_IOCTL, &command );
然后确实有必要切换界面 altsetting
struct usbdevfs_setinterface setif;
setif.altsetting = 1;
setif.interface = 1;
ioctl(fd, USBDEVFS_SETINTERFACE, &setif);
否则,端点将像初始时一样不可用 post(至少在我的 USB 设备中)