1 package org.libsdl.app;
3 import android.hardware.usb.*;
4 import android.os.Build;
5 import android.util.Log;
6 import java.util.Arrays;
8 class HIDDeviceUSB implements HIDDevice {
10 private static final String TAG = "hidapi";
12 protected HIDDeviceManager mManager;
13 protected UsbDevice mDevice;
14 protected int mInterfaceIndex;
15 protected int mInterface;
16 protected int mDeviceId;
17 protected UsbDeviceConnection mConnection;
18 protected UsbEndpoint mInputEndpoint;
19 protected UsbEndpoint mOutputEndpoint;
20 protected InputThread mInputThread;
21 protected boolean mRunning;
22 protected boolean mFrozen;
24 public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) {
27 mInterfaceIndex = interface_index;
28 mInterface = mDevice.getInterface(mInterfaceIndex).getId();
29 mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
33 public String getIdentifier() {
34 return String.format("%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterfaceIndex);
43 public int getVendorId() {
44 return mDevice.getVendorId();
48 public int getProductId() {
49 return mDevice.getProductId();
53 public String getSerialNumber() {
55 if (Build.VERSION.SDK_INT >= 21) {
56 result = mDevice.getSerialNumber();
65 public int getVersion() {
70 public String getManufacturerName() {
72 if (Build.VERSION.SDK_INT >= 21) {
73 result = mDevice.getManufacturerName();
76 result = String.format("%x", getVendorId());
82 public String getProductName() {
84 if (Build.VERSION.SDK_INT >= 21) {
85 result = mDevice.getProductName();
88 result = String.format("%x", getProductId());
94 public UsbDevice getDevice() {
98 public String getDeviceName() {
99 return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
103 public boolean open() {
104 mConnection = mManager.getUSBManager().openDevice(mDevice);
105 if (mConnection == null) {
106 Log.w(TAG, "Unable to open USB device " + getDeviceName());
110 // Force claim our interface
111 UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
112 if (!mConnection.claimInterface(iface, true)) {
113 Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
118 // Find the endpoints
119 for (int j = 0; j < iface.getEndpointCount(); j++) {
120 UsbEndpoint endpt = iface.getEndpoint(j);
121 switch (endpt.getDirection()) {
122 case UsbConstants.USB_DIR_IN:
123 if (mInputEndpoint == null) {
124 mInputEndpoint = endpt;
127 case UsbConstants.USB_DIR_OUT:
128 if (mOutputEndpoint == null) {
129 mOutputEndpoint = endpt;
135 // Make sure the required endpoints were present
136 if (mInputEndpoint == null || mOutputEndpoint == null) {
137 Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
142 // Start listening for input
144 mInputThread = new InputThread();
145 mInputThread.start();
151 public int sendFeatureReport(byte[] report) {
154 int length = report.length;
155 boolean skipped_report_id = false;
156 byte report_number = report[0];
158 if (report_number == 0x0) {
161 skipped_report_id = true;
164 res = mConnection.controlTransfer(
165 UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_OUT,
166 0x09/*HID set_report*/,
167 (3/*HID feature*/ << 8) | report_number,
169 report, offset, length,
170 1000/*timeout millis*/);
173 Log.w(TAG, "sendFeatureReport() returned " + res + " on device " + getDeviceName());
177 if (skipped_report_id) {
184 public int sendOutputReport(byte[] report) {
185 int r = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
186 if (r != report.length) {
187 Log.w(TAG, "sendOutputReport() returned " + r + " on device " + getDeviceName());
193 public boolean getFeatureReport(byte[] report) {
196 int length = report.length;
197 boolean skipped_report_id = false;
198 byte report_number = report[0];
200 if (report_number == 0x0) {
201 /* Offset the return buffer by 1, so that the report ID
202 will remain in byte 0. */
205 skipped_report_id = true;
208 res = mConnection.controlTransfer(
209 UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_IN,
210 0x01/*HID get_report*/,
211 (3/*HID feature*/ << 8) | report_number,
213 report, offset, length,
214 1000/*timeout millis*/);
217 Log.w(TAG, "getFeatureReport() returned " + res + " on device " + getDeviceName());
221 if (skipped_report_id) {
230 data = Arrays.copyOfRange(report, 0, res);
232 mManager.HIDDeviceFeatureReport(mDeviceId, data);
238 public void close() {
240 if (mInputThread != null) {
241 while (mInputThread.isAlive()) {
242 mInputThread.interrupt();
245 } catch (InterruptedException e) {
246 // Keep trying until we're done
251 if (mConnection != null) {
252 UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
253 mConnection.releaseInterface(iface);
260 public void shutdown() {
266 public void setFrozen(boolean frozen) {
270 protected class InputThread extends Thread {
273 int packetSize = mInputEndpoint.getMaxPacketSize();
274 byte[] packet = new byte[packetSize];
279 r = mConnection.bulkTransfer(mInputEndpoint, packet, packetSize, 1000);
283 Log.v(TAG, "Exception in UsbDeviceConnection bulktransfer: " + e);
287 // Could be a timeout or an I/O error
291 if (r == packetSize) {
294 data = Arrays.copyOfRange(packet, 0, r);
298 mManager.HIDDeviceInputReport(mDeviceId, data);