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
17package android.hardware.usb;
18
19import android.util.Log;
20
21import 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 */
35public class UsbRequest {
36
37    private static final String TAG = "UsbRequest";
38
39    // used by the JNI code
40    private int 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