美文网首页
HDMI外接USB设备数据传输流程

HDMI外接USB设备数据传输流程

作者: 赛非斯 | 来源:发表于2021-09-29 00:00 被阅读0次
    • 主机通过HID协议与USB设备通信,Google提供了controlTransfer和bulkTransfer的方式
      frameworks/base/core/java/android/hardware/usb/UsbDeviceConnection.java
      bulkTransfer是通过筛选endpoint的方式,controlTransfer 则是根据协议定义好的这三个参数
      (int requestType, int request, int value, int index)
     public int controlTransfer(int requestType, int request, int value, int index,
                byte[] buffer, int offset, int length, int timeout) {
            checkBounds(buffer, offset, length);
            return native_control_request(requestType, request, value, index,
                    buffer, offset, length, timeout);
        }
        public int bulkTransfer(UsbEndpoint endpoint,
                byte[] buffer, int length, int timeout) {
            return bulkTransfer(endpoint, buffer, 0, length, timeout);
        }
    
    • 每个usb pidvid提供好几个interface通道 ,每个interface提供最多俩endpoint

    06-28 12:55:36.964 D/UsbHostManager( 1580): UsbConfiguration[mId=1,mName=USB-3.0,mAttributes=224,mMaxPower=112,mInterfaces=[
    06-28 12:55:36.964 D/UsbHostManager( 1580): UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=14,mSubclass=1,mProtocol=0,mEndpoints=[
    06-28 12:55:36.964 D/UsbHostManager( 1580): UsbEndpoint[mAddress=130,mAttributes=3,mMaxPacketSize=64,mInterval=4]]
    06-28 12:55:36.964 D/UsbHostManager( 1580): UsbInterface[mId=1,mAlternateSetting=0,mName=null,mClass=14,mSubclass=2,mProtocol=0,mEndpoints=[]
    06-28 12:55:36.964 D/UsbHostManager( 1580): UsbInterface[mId=1,mAlternateSetting=1,mName=null,mClass=14,mSubclass=2,mProtocol=0,mEndpoints=[
    06-28 12:55:36.964 D/UsbHostManager( 1580): UsbEndpoint[mAddress=131,mAttributes=5,mMaxPacketSize=1024,mInterval=1

    public static final int USB_DIR_OUT = ServiceProtoEnums.USB_ENDPOINT_DIR_OUT; // 0
    public static final int USB_DIR_IN = ServiceProtoEnums.USB_ENDPOINT_DIR_IN; // 0x80
    

    所以mAddress值表示in还是out

    大于128 是 1 in
    小于128 是 0 out

    上面两种方式都可以读写数据。今天我们重点讲另外一种读取数据的方式,这种方式是阻塞式的,就是没有数据的时候等待,有数据的时候读取数据。

    USBREQUEST 实现异步接收数据

    简单写个例子

    ByteBuffer buffer = ByteBuffer.allocate(4096);
    buffer.order(ByteOrder.LITTLE_ENDIAN);
    UsbRequest request = new UsbRequest();
    request.initialize(mConnection, mEndpointIn);
    request.queue(buffer, 4096);
    
    if (mConnection.requestWait() == request) {
       byte[] data = buffer.array();
    }
    

    它提供的API如下


    20210928224938.png
    • 下面我们看看读取数据的接口 public boolean queue(@Nullable ByteBuffer buffer)
      我把核心代码挑出来
      request->client_data = (void *)env->NewGlobalRef(thiz); //为了waitRequest能找到我们

      int err = usb_request_queue(request); // 调用到libusb的实现

    frameworks/base/core/java/android/hardware/usb/UsbRequest.java
        public boolean queue(@Nullable ByteBuffer buffer) {
            // Request need to be initialized
            Preconditions.checkState(mNativeContext != 0, "request is not initialized");
    
            // Request can not be currently queued
            Preconditions.checkState(!mIsUsingNewQueue, "this request is currently queued");
    
            boolean isSend = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
            boolean wasQueued;
    
            synchronized (mLock) {
                mBuffer = buffer;
    
                if (buffer == null) {
                    // Null buffers enqueue empty USB requests which is supported
                    mIsUsingNewQueue = true;
                    wasQueued = native_queue(null, 0, 0);
                } else {
                    if (mConnection.getContext().getApplicationInfo().targetSdkVersion
                            < Build.VERSION_CODES.P) {
                        // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
                        Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
                                "number of remaining bytes");
                    }
    
                    // Can not receive into read-only buffers.
                    Preconditions.checkArgument(!(buffer.isReadOnly() && !isSend), "buffer can not be "
                            + "read-only when receiving data");
    
                    if (!buffer.isDirect()) {
                        mTempBuffer = ByteBuffer.allocateDirect(mBuffer.remaining());
    
                        if (isSend) {
                            // Copy buffer into temporary buffer
                            mBuffer.mark();
                            mTempBuffer.put(mBuffer);
                            mTempBuffer.flip();
                            mBuffer.reset();
                        }
    
                        // Send/Receive into the temp buffer instead
                        buffer = mTempBuffer;
                    }
    
                    mIsUsingNewQueue = true;
                    wasQueued = native_queue(buffer, buffer.position(), buffer.remaining());
                }
            }
    
            if (!wasQueued) {
                mIsUsingNewQueue = false;
                mTempBuffer = null;
                mBuffer = null;
            }
    
            return wasQueued;
        }
    //private native boolean native_queue(ByteBuffer buffer, int offset, int length); 
    //接着看native方法的实现
    frameworks/base/core/jni/android_hardware_UsbRequest.cpp
    static jboolean
    android_hardware_UsbRequest_queue(JNIEnv *env, jobject thiz, jobject buffer, jint offset,
            jint length)
    {
        struct usb_request* request = get_request_from_object(env, thiz);
        if (!request) {
            ALOGE("request is closed in native_queue");
            return JNI_FALSE;
        }
    
        if (buffer == NULL) {
            request->buffer = NULL;
            request->buffer_length = 0;
        } else {
            request->buffer = (void *)((char *)env->GetDirectBufferAddress(buffer) + offset);
            request->buffer_length = length;
        }
    
        // Save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us.
        // We also need this to make sure our native buffer is not deallocated while IO is active.
        request->client_data = (void *)env->NewGlobalRef(thiz);
    
        int err = usb_request_queue(request);
    
        if (err != 0) {
            request->buffer = NULL;
            env->DeleteGlobalRef((jobject)request->client_data);
            return JNI_FALSE;
        }
        return JNI_TRUE;
    }
    
    • 从usb_request_queue 继续往下看代码,看到这个while循环是不是理解了,没有数据的时候就会在这等着。
      有数据了就会往 req->buffer 也就是 queue(@Nullable ByteBuffer buffer) buffer里塞数据了。
      \system\core\libusbhost\usbhost.c
    int usb_request_queue(struct usb_request *req)
    {
        struct usbdevfs_urb *urb = (struct usbdevfs_urb*)req->private_data;
        int res;
    
        urb->status = -1;
        urb->buffer = req->buffer;
        urb->buffer_length = req->buffer_length;
    
        do {
            res = ioctl(req->dev->fd, USBDEVFS_SUBMITURB, urb);//这里就往驱动发明了
        } while((res < 0) && (errno == EINTR));
    
        return res;
    }
    

    相关文章

      网友评论

          本文标题:HDMI外接USB设备数据传输流程

          本文链接:https://www.haomeiwen.com/subject/ytyhnltx.html