1 /** 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * <p>http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * <p>Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 * express or implied. See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 package android.car.usb.handler; 15 16 import android.hardware.usb.UsbConstants; 17 import android.hardware.usb.UsbDevice; 18 import android.hardware.usb.UsbDeviceConnection; 19 import android.util.Log; 20 import java.io.IOException; 21 22 final class AoapInterface { 23 /** 24 * Use Google Vendor ID when in accessory mode 25 */ 26 public static final int USB_ACCESSORY_VENDOR_ID = 0x18D1; 27 28 /** 29 * Product ID to use when in accessory mode 30 */ 31 public static final int USB_ACCESSORY_PRODUCT_ID = 0x2D00; 32 33 /** 34 * Product ID to use when in accessory mode and adb is enabled 35 */ 36 public static final int USB_ACCESSORY_ADB_PRODUCT_ID = 0x2D01; 37 38 /** 39 * Indexes for strings sent by the host via ACCESSORY_SEND_STRING 40 */ 41 public static final int ACCESSORY_STRING_MANUFACTURER = 0; 42 public static final int ACCESSORY_STRING_MODEL = 1; 43 public static final int ACCESSORY_STRING_DESCRIPTION = 2; 44 public static final int ACCESSORY_STRING_VERSION = 3; 45 public static final int ACCESSORY_STRING_URI = 4; 46 public static final int ACCESSORY_STRING_SERIAL = 5; 47 48 /** 49 * Control request for retrieving device's protocol version 50 * 51 * requestType: USB_DIR_IN | USB_TYPE_VENDOR 52 * request: ACCESSORY_GET_PROTOCOL 53 * value: 0 54 * index: 0 55 * data version number (16 bits little endian) 56 * 1 for original accessory support 57 * 2 adds HID and device to host audio support 58 */ 59 public static final int ACCESSORY_GET_PROTOCOL = 51; 60 61 /** 62 * Control request for host to send a string to the device 63 * 64 * requestType: USB_DIR_OUT | USB_TYPE_VENDOR 65 * request: ACCESSORY_SEND_STRING 66 * value: 0 67 * index: string ID 68 * data zero terminated UTF8 string 69 * 70 * The device can later retrieve these strings via the 71 * ACCESSORY_GET_STRING_* ioctls 72 */ 73 public static final int ACCESSORY_SEND_STRING = 52; 74 75 /** 76 * Control request for starting device in accessory mode. 77 * The host sends this after setting all its strings to the device. 78 * 79 * requestType: USB_DIR_OUT | USB_TYPE_VENDOR 80 * request: ACCESSORY_START 81 * value: 0 82 * index: 0 83 * data none 84 */ 85 public static final int ACCESSORY_START = 53; 86 87 /** 88 * Max payload size for AOAP. Limited by driver. 89 */ 90 public static final int MAX_PAYLOAD_SIZE = 16384; 91 92 /** 93 * Accessory write timeout. 94 */ 95 public static final int AOAP_TIMEOUT_MS = 2000; 96 97 private static final String TAG = AoapInterface.class.getSimpleName(); 98 getProtocol(UsbDeviceConnection conn)99 public static int getProtocol(UsbDeviceConnection conn) { 100 byte[] buffer = new byte[2]; 101 int len = conn.controlTransfer( 102 UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR, 103 ACCESSORY_GET_PROTOCOL, 0, 0, buffer, 2, AOAP_TIMEOUT_MS); 104 if (len != 2) { 105 return -1; 106 } 107 return (buffer[1] << 8) | buffer[0]; 108 } 109 isSupported(UsbDeviceConnection conn)110 public static boolean isSupported(UsbDeviceConnection conn) { 111 return getProtocol(conn) >= 1; 112 } 113 sendString(UsbDeviceConnection conn, int index, String string)114 public static void sendString(UsbDeviceConnection conn, int index, String string) 115 throws IOException { 116 byte[] buffer = (string + "\0").getBytes(); 117 int len = conn.controlTransfer( 118 UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR, 119 ACCESSORY_SEND_STRING, 0, index, 120 buffer, buffer.length, AOAP_TIMEOUT_MS); 121 if (len != buffer.length) { 122 throw new IOException("Failed to send string " + index + ": \"" + string + "\""); 123 } else { 124 Log.i(TAG, "Sent string " + index + ": \"" + string + "\""); 125 } 126 } 127 sendAoapStart(UsbDeviceConnection conn)128 public static void sendAoapStart(UsbDeviceConnection conn) throws IOException { 129 int len = conn.controlTransfer( 130 UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR, 131 ACCESSORY_START, 0, 0, null, 0, AOAP_TIMEOUT_MS); 132 if (len < 0) { 133 throw new IOException("Control transfer for accessory start failed: " + len); 134 } 135 } 136 isDeviceInAoapMode(UsbDevice device)137 public static boolean isDeviceInAoapMode(UsbDevice device) { 138 if (device == null) { 139 return false; 140 } 141 final int vid = device.getVendorId(); 142 final int pid = device.getProductId(); 143 return vid == USB_ACCESSORY_VENDOR_ID 144 && (pid == USB_ACCESSORY_PRODUCT_ID || pid == USB_ACCESSORY_ADB_PRODUCT_ID); 145 } 146 } 147