1/*
2 * Copyright (C) 2011 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.os.ParcelFileDescriptor;
20
21import java.io.FileDescriptor;
22
23
24/**
25 * This class is used for sending and receiving data and control messages to a USB device.
26 * Instances of this class are created by {@link UsbManager#openDevice}.
27 */
28public class UsbDeviceConnection {
29
30    private static final String TAG = "UsbDeviceConnection";
31
32    private final UsbDevice mDevice;
33
34    // used by the JNI code
35    private int mNativeContext;
36
37    /**
38     * UsbDevice should only be instantiated by UsbService implementation
39     * @hide
40     */
41    public UsbDeviceConnection(UsbDevice device) {
42        mDevice = device;
43    }
44
45    /* package */ boolean open(String name, ParcelFileDescriptor pfd) {
46        return native_open(name, pfd.getFileDescriptor());
47    }
48
49    /**
50     * Releases all system resources related to the device.
51     * Once the object is closed it cannot be used again.
52     * The client must call {@link UsbManager#openDevice} again
53     * to retrieve a new instance to reestablish communication with the device.
54     */
55    public void close() {
56        native_close();
57    }
58
59    /**
60     * Returns the native file descriptor for the device, or
61     * -1 if the device is not opened.
62     * This is intended for passing to native code to access the device.
63     *
64     * @return the native file descriptor
65     */
66    public int getFileDescriptor() {
67        return native_get_fd();
68    }
69
70    /**
71     * Returns the raw USB descriptors for the device.
72     * This can be used to access descriptors not supported directly
73     * via the higher level APIs.
74     *
75     * @return raw USB descriptors
76     */
77    public byte[] getRawDescriptors() {
78        return native_get_desc();
79    }
80
81    /**
82     * Claims exclusive access to a {@link android.hardware.usb.UsbInterface}.
83     * This must be done before sending or receiving data on any
84     * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface.
85     *
86     * @param intf the interface to claim
87     * @param force true to disconnect kernel driver if necessary
88     * @return true if the interface was successfully claimed
89     */
90    public boolean claimInterface(UsbInterface intf, boolean force) {
91        return native_claim_interface(intf.getId(), force);
92    }
93
94    /**
95     * Releases exclusive access to a {@link android.hardware.usb.UsbInterface}.
96     *
97     * @return true if the interface was successfully released
98     */
99    public boolean releaseInterface(UsbInterface intf) {
100        return native_release_interface(intf.getId());
101    }
102
103    /**
104     * Performs a control transaction on endpoint zero for this device.
105     * The direction of the transfer is determined by the request type.
106     * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
107     * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
108     * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
109     * is a read.
110     * <p>
111     * This method transfers data starting from index 0 in the buffer.
112     * To specify a different offset, use
113     * {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}.
114     * </p>
115     *
116     * @param requestType request type for this transaction
117     * @param request request ID for this transaction
118     * @param value value field for this transaction
119     * @param index index field for this transaction
120     * @param buffer buffer for data portion of transaction,
121     * or null if no data needs to be sent or received
122     * @param length the length of the data to send or receive
123     * @param timeout in milliseconds
124     * @return length of data transferred (or zero) for success,
125     * or negative value for failure
126     */
127    public int controlTransfer(int requestType, int request, int value,
128            int index, byte[] buffer, int length, int timeout) {
129        return controlTransfer(requestType, request, value, index, buffer, 0, length, timeout);
130    }
131
132    /**
133     * Performs a control transaction on endpoint zero for this device.
134     * The direction of the transfer is determined by the request type.
135     * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
136     * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
137     * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
138     * is a read.
139     *
140     * @param requestType request type for this transaction
141     * @param request request ID for this transaction
142     * @param value value field for this transaction
143     * @param index index field for this transaction
144     * @param buffer buffer for data portion of transaction,
145     * or null if no data needs to be sent or received
146     * @param offset the index of the first byte in the buffer to send or receive
147     * @param length the length of the data to send or receive
148     * @param timeout in milliseconds
149     * @return length of data transferred (or zero) for success,
150     * or negative value for failure
151     */
152    public int controlTransfer(int requestType, int request, int value, int index,
153            byte[] buffer, int offset, int length, int timeout) {
154        checkBounds(buffer, offset, length);
155        return native_control_request(requestType, request, value, index,
156                buffer, offset, length, timeout);
157    }
158
159    /**
160     * Performs a bulk transaction on the given endpoint.
161     * The direction of the transfer is determined by the direction of the endpoint.
162     * <p>
163     * This method transfers data starting from index 0 in the buffer.
164     * To specify a different offset, use
165     * {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)}.
166     * </p>
167     *
168     * @param endpoint the endpoint for this transaction
169     * @param buffer buffer for data to send or receive
170     * @param length the length of the data to send or receive
171     * @param timeout in milliseconds
172     * @return length of data transferred (or zero) for success,
173     * or negative value for failure
174     */
175    public int bulkTransfer(UsbEndpoint endpoint,
176            byte[] buffer, int length, int timeout) {
177        return bulkTransfer(endpoint, buffer, 0, length, timeout);
178    }
179
180    /**
181     * Performs a bulk transaction on the given endpoint.
182     * The direction of the transfer is determined by the direction of the endpoint.
183     *
184     * @param endpoint the endpoint for this transaction
185     * @param buffer buffer for data to send or receive
186     * @param offset the index of the first byte in the buffer to send or receive
187     * @param length the length of the data to send or receive
188     * @param timeout in milliseconds
189     * @return length of data transferred (or zero) for success,
190     * or negative value for failure
191     */
192    public int bulkTransfer(UsbEndpoint endpoint,
193            byte[] buffer, int offset, int length, int timeout) {
194        checkBounds(buffer, offset, length);
195        return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout);
196    }
197
198    /**
199     * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation
200     * Note that this may return requests queued on multiple
201     * {@link android.hardware.usb.UsbEndpoint}s.
202     * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and
203     * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining
204     * how to process the result of this function.
205     *
206     * @return a completed USB request, or null if an error occurred
207     */
208    public UsbRequest requestWait() {
209        UsbRequest request = native_request_wait();
210        if (request != null) {
211            request.dequeue();
212        }
213        return request;
214    }
215
216    /**
217     * Returns the serial number for the device.
218     * This will return null if the device has not been opened.
219     *
220     * @return the device serial number
221     */
222    public String getSerial() {
223        return native_get_serial();
224    }
225
226    private static void checkBounds(byte[] buffer, int start, int length) {
227        final int bufferLength = (buffer != null ? buffer.length : 0);
228        if (start < 0 || start + length > bufferLength) {
229            throw new IllegalArgumentException("Buffer start or length out of bounds.");
230        }
231    }
232
233    private native boolean native_open(String deviceName, FileDescriptor pfd);
234    private native void native_close();
235    private native int native_get_fd();
236    private native byte[] native_get_desc();
237    private native boolean native_claim_interface(int interfaceID, boolean force);
238    private native boolean native_release_interface(int interfaceID);
239    private native int native_control_request(int requestType, int request, int value,
240            int index, byte[] buffer, int offset, int length, int timeout);
241    private native int native_bulk_request(int endpoint, byte[] buffer,
242            int offset, int length, int timeout);
243    private native UsbRequest native_request_wait();
244    private native String native_get_serial();
245}
246