• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 package com.android.helper.aoa;
17 
18 import static com.android.helper.aoa.AoaDevice.ACCESSORY_GET_PROTOCOL;
19 import static com.android.helper.aoa.AoaDevice.INPUT;
20 
21 import static com.google.common.base.Preconditions.checkNotNull;
22 
23 import com.google.common.primitives.Shorts;
24 import com.sun.jna.Pointer;
25 import com.sun.jna.ptr.PointerByReference;
26 
27 import javax.annotation.Nonnull;
28 import javax.annotation.Nullable;
29 
30 /** Connected USB device. */
31 public class UsbDevice implements AutoCloseable {
32 
33     private final IUsbNative mUsb;
34     private final byte[] mDescriptor = new byte[18];
35     private Pointer mHandle;
36 
UsbDevice(@onnull IUsbNative usb, @Nonnull Pointer devicePointer)37     UsbDevice(@Nonnull IUsbNative usb, @Nonnull Pointer devicePointer) {
38         mUsb = usb;
39 
40         // retrieve device descriptor
41         mUsb.libusb_get_device_descriptor(devicePointer, mDescriptor);
42 
43         // obtain device handle
44         PointerByReference handle = new PointerByReference();
45         mUsb.libusb_open(devicePointer, handle);
46         mHandle = handle.getValue();
47     }
48 
49     /**
50      * Performs a synchronous control transaction with unlimited timeout.
51      *
52      * @return number of bytes transferred, or an error code
53      */
controlTransfer(byte requestType, byte request, int value, int index, byte[] data)54     public int controlTransfer(byte requestType, byte request, int value, int index, byte[] data) {
55         return mUsb.libusb_control_transfer(
56                 checkNotNull(mHandle),
57                 requestType,
58                 request,
59                 (short) value,
60                 (short) index,
61                 data,
62                 (short) data.length,
63                 0);
64     }
65 
66     /**
67      * Performs a USB port reset. A LIBUSB_ERROR_NOT_FOUND error may indicate that the connection
68      * was reset, but that this {@link UsbDevice} is no longer valid and needs to be recreated.
69      *
70      * @return 0 on success or error code
71      */
reset()72     public int reset() {
73         return mUsb.libusb_reset_device(checkNotNull(mHandle));
74     }
75 
76     /** @return true if device handle is non-null, but does not check if resetting is necessary */
isValid()77     public boolean isValid() {
78         return mHandle != null;
79     }
80 
81     /** @return device's serial number or {@code null} if serial could not be determined */
82     @Nullable
getSerialNumber()83     public String getSerialNumber() {
84         if (!isValid() || mDescriptor[16] <= 0) {
85             // no device handle or string index is invalid
86             return null;
87         }
88 
89         byte[] data = new byte[64];
90         int length = mUsb.libusb_get_string_descriptor_ascii(mHandle, mDescriptor[16], data, 64);
91         return length > 0 ? new String(data, 0, length) : null;
92     }
93 
94     /** @return device's vendor ID */
getVendorId()95     public int getVendorId() {
96         return Shorts.fromBytes(mDescriptor[9], mDescriptor[8]);
97     }
98 
99     /** @return device's product ID */
getProductId()100     public int getProductId() {
101         return Shorts.fromBytes(mDescriptor[11], mDescriptor[10]);
102     }
103 
104     /** @return true if device is AOAv2-compatible */
isAoaCompatible()105     public boolean isAoaCompatible() {
106         return isValid() && controlTransfer(INPUT, ACCESSORY_GET_PROTOCOL, 0, 0, new byte[2]) >= 2;
107     }
108 
109     /** Close the connection if necessary. */
110     @Override
close()111     public void close() {
112         if (isValid()) {
113             mUsb.libusb_close(mHandle);
114             mHandle = null;
115         }
116     }
117 }
118