Home | History | Annotate | Download | only in usb
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.hardware.usb;
     18 
     19 import android.util.Log;
     20 
     21 import java.nio.ByteBuffer;
     22 
     23 /**
     24  * A class representing USB request packet.
     25  * This can be used for both reading and writing data to or from a
     26  * {@link android.hardware.usb.UsbDeviceConnection}.
     27  * UsbRequests can be used to transfer data on bulk and interrupt endpoints.
     28  * Requests on bulk endpoints can be sent synchronously via {@link UsbDeviceConnection#bulkTransfer}
     29  * or asynchronously via {@link #queue} and {@link UsbDeviceConnection#requestWait}.
     30  * Requests on interrupt endpoints are only send and received asynchronously.
     31  *
     32  * <p>Requests on endpoint zero are not supported by this class;
     33  * use {@link UsbDeviceConnection#controlTransfer} for endpoint zero requests instead.
     34  */
     35 public class UsbRequest {
     36 
     37     private static final String TAG = "UsbRequest";
     38 
     39     // used by the JNI code
     40     private long mNativeContext;
     41 
     42     private UsbEndpoint mEndpoint;
     43 
     44     // for temporarily saving current buffer across queue and dequeue
     45     private ByteBuffer mBuffer;
     46     private int mLength;
     47 
     48     // for client use
     49     private Object mClientData;
     50 
     51     public UsbRequest() {
     52     }
     53 
     54     /**
     55      * Initializes the request so it can read or write data on the given endpoint.
     56      * Whether the request allows reading or writing depends on the direction of the endpoint.
     57      *
     58      * @param endpoint the endpoint to be used for this request.
     59      * @return true if the request was successfully opened.
     60      */
     61     public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint) {
     62         mEndpoint = endpoint;
     63         return native_init(connection, endpoint.getAddress(), endpoint.getAttributes(),
     64                 endpoint.getMaxPacketSize(), endpoint.getInterval());
     65     }
     66 
     67     /**
     68      * Releases all resources related to this request.
     69      */
     70     public void close() {
     71         mEndpoint = null;
     72         native_close();
     73     }
     74 
     75     @Override
     76     protected void finalize() throws Throwable {
     77         try {
     78             if (mEndpoint != null) {
     79                 Log.v(TAG, "endpoint still open in finalize(): " + this);
     80                 close();
     81             }
     82         } finally {
     83             super.finalize();
     84         }
     85     }
     86 
     87     /**
     88      * Returns the endpoint for the request, or null if the request is not opened.
     89      *
     90      * @return the request's endpoint
     91      */
     92     public UsbEndpoint getEndpoint() {
     93         return mEndpoint;
     94     }
     95 
     96     /**
     97      * Returns the client data for the request.
     98      * This can be used in conjunction with {@link #setClientData}
     99      * to associate another object with this request, which can be useful for
    100      * maintaining state between calls to {@link #queue} and
    101      * {@link android.hardware.usb.UsbDeviceConnection#requestWait}
    102      *
    103      * @return the client data for the request
    104      */
    105     public Object getClientData() {
    106         return mClientData;
    107     }
    108 
    109     /**
    110      * Sets the client data for the request.
    111      * This can be used in conjunction with {@link #getClientData}
    112      * to associate another object with this request, which can be useful for
    113      * maintaining state between calls to {@link #queue} and
    114      * {@link android.hardware.usb.UsbDeviceConnection#requestWait}
    115      *
    116      * @param data the client data for the request
    117      */
    118     public void setClientData(Object data) {
    119         mClientData = data;
    120     }
    121 
    122     /**
    123      * Queues the request to send or receive data on its endpoint.
    124      * For OUT endpoints, the given buffer data will be sent on the endpoint.
    125      * For IN endpoints, the endpoint will attempt to read the given number of bytes
    126      * into the specified buffer.
    127      * If the queueing operation is successful, we return true and the result will be
    128      * returned via {@link android.hardware.usb.UsbDeviceConnection#requestWait}
    129      *
    130      * @param buffer the buffer containing the bytes to write, or location to store
    131      * the results of a read
    132      * @param length number of bytes to read or write
    133      * @return true if the queueing operation succeeded
    134      */
    135     public boolean queue(ByteBuffer buffer, int length) {
    136         boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
    137         boolean result;
    138         if (buffer.isDirect()) {
    139             result = native_queue_direct(buffer, length, out);
    140         } else if (buffer.hasArray()) {
    141             result = native_queue_array(buffer.array(), length, out);
    142         } else {
    143             throw new IllegalArgumentException("buffer is not direct and has no array");
    144         }
    145         if (result) {
    146             // save our buffer for when the request has completed
    147             mBuffer = buffer;
    148             mLength = length;
    149         }
    150         return result;
    151     }
    152 
    153     /* package */ void dequeue() {
    154         boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
    155         int bytesRead;
    156         if (mBuffer.isDirect()) {
    157             bytesRead = native_dequeue_direct();
    158         } else {
    159             bytesRead = native_dequeue_array(mBuffer.array(), mLength, out);
    160         }
    161         if (bytesRead >= 0) {
    162             mBuffer.position(Math.min(bytesRead, mLength));
    163         }
    164         mBuffer = null;
    165         mLength = 0;
    166     }
    167 
    168     /**
    169      * Cancels a pending queue operation.
    170      *
    171      * @return true if cancelling succeeded
    172      */
    173     public boolean cancel() {
    174         return native_cancel();
    175     }
    176 
    177     private native boolean native_init(UsbDeviceConnection connection, int ep_address,
    178             int ep_attributes, int ep_max_packet_size, int ep_interval);
    179     private native void native_close();
    180     private native boolean native_queue_array(byte[] buffer, int length, boolean out);
    181     private native int native_dequeue_array(byte[] buffer, int length, boolean out);
    182     private native boolean native_queue_direct(ByteBuffer buffer, int length, boolean out);
    183     private native int native_dequeue_direct();
    184     private native boolean native_cancel();
    185 }
    186