1 /*
2  * Copyright (C) 2017 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.server.usb.descriptors;
17 
18 import android.hardware.usb.UsbConfiguration;
19 import android.hardware.usb.UsbDevice;
20 import android.util.Log;
21 
22 import com.android.server.usb.descriptors.report.ReportCanvas;
23 import com.android.server.usb.descriptors.report.UsbStrings;
24 
25 import java.util.ArrayList;
26 
27 /**
28  * @hide
29  * A USB Device Descriptor.
30  * see usb11.pdf section 9.6.1
31  */
32 public final class UsbDeviceDescriptor extends UsbDescriptor {
33     private static final String TAG = "UsbDeviceDescriptor";
34     private static final boolean DEBUG = false;
35 
36     public static final int USBSPEC_1_0 = 0x0100;
37     public static final int USBSPEC_1_1 = 0x0110;
38     public static final int USBSPEC_2_0 = 0x0200;
39 
40     private int mSpec;          // 2:2 bcdUSB 2 BCD USB Specification Number - BCD
41     private int mDevClass;      // 4:1 class code
42     private int mDevSubClass;   // 5:1 subclass code
43     private int mProtocol;      // 6:1 protocol
44     private byte mPacketSize;   // 7:1 Maximum Packet Size for Zero Endpoint.
45                                 // Valid Sizes are 8, 16, 32, 64
46     private int mVendorID;      // 8:2 vendor ID
47     private int mProductID;     // 10:2 product ID
48     private int mDeviceRelease; // 12:2 Device Release number - BCD
49     private byte mMfgIndex;     // 14:1 Index of Manufacturer String Descriptor
50     private byte mProductIndex; // 15:1 Index of Product String Descriptor
51     private byte mSerialIndex;  // 16:1 Index of Serial Number String Descriptor
52     private byte mNumConfigs;   // 17:1 Number of Possible Configurations
53 
54     private ArrayList<UsbConfigDescriptor> mConfigDescriptors =
55             new ArrayList<UsbConfigDescriptor>();
56 
UsbDeviceDescriptor(int length, byte type)57     UsbDeviceDescriptor(int length, byte type) {
58         super(length, type);
59         mHierarchyLevel = 1;
60     }
61 
getSpec()62     public int getSpec() {
63         return mSpec;
64     }
65 
getDevClass()66     public int getDevClass() {
67         return mDevClass;
68     }
69 
getDevSubClass()70     public int getDevSubClass() {
71         return mDevSubClass;
72     }
73 
getProtocol()74     public int getProtocol() {
75         return mProtocol;
76     }
77 
getPacketSize()78     public byte getPacketSize() {
79         return mPacketSize;
80     }
81 
getVendorID()82     public int getVendorID() {
83         return mVendorID;
84     }
85 
getProductID()86     public int getProductID() {
87         return mProductID;
88     }
89 
getDeviceRelease()90     public int getDeviceRelease() {
91         return mDeviceRelease;
92     }
93 
94     // mDeviceRelease is binary-coded decimal, format DD.DD
getDeviceReleaseString()95     public String getDeviceReleaseString() {
96         int hundredths = mDeviceRelease & 0xF;
97         int tenths = (mDeviceRelease & 0xF0) >> 4;
98         int ones = (mDeviceRelease & 0xF00) >> 8;
99         int tens = (mDeviceRelease & 0xF000) >> 12;
100         return String.format("%d.%d%d", tens * 10 + ones, tenths, hundredths);
101     }
102 
getMfgIndex()103     public byte getMfgIndex() {
104         return mMfgIndex;
105     }
106 
getMfgString(UsbDescriptorParser p)107     public String getMfgString(UsbDescriptorParser p) {
108         return p.getDescriptorString(mMfgIndex);
109     }
110 
getProductIndex()111     public byte getProductIndex() {
112         return mProductIndex;
113     }
114 
getProductString(UsbDescriptorParser p)115     public String getProductString(UsbDescriptorParser p) {
116         return p.getDescriptorString(mProductIndex);
117     }
118 
getSerialIndex()119     public byte getSerialIndex() {
120         return mSerialIndex;
121     }
122 
getSerialString(UsbDescriptorParser p)123     public String getSerialString(UsbDescriptorParser p) {
124         return p.getDescriptorString(mSerialIndex);
125     }
126 
getNumConfigs()127     public byte getNumConfigs() {
128         return mNumConfigs;
129     }
130 
addConfigDescriptor(UsbConfigDescriptor config)131     void addConfigDescriptor(UsbConfigDescriptor config) {
132         mConfigDescriptors.add(config);
133     }
134 
135     /**
136      * @hide
137      */
toAndroid(UsbDescriptorParser parser)138     public UsbDevice.Builder toAndroid(UsbDescriptorParser parser) {
139         if (DEBUG) {
140             Log.d(TAG, "toAndroid()");
141         }
142 
143         String mfgName = getMfgString(parser);
144         String prodName = getProductString(parser);
145         if (DEBUG) {
146             Log.d(TAG, "  mfgName:" + mfgName + " prodName:" + prodName);
147         }
148 
149         String versionString = getDeviceReleaseString();
150         String serialStr = getSerialString(parser);
151         if (DEBUG) {
152             Log.d(TAG, "  versionString:" + versionString + " serialStr:" + serialStr);
153         }
154 
155         UsbConfiguration[] configs = new UsbConfiguration[mConfigDescriptors.size()];
156         Log.d(TAG, "  " + configs.length + " configs");
157         for (int index = 0; index < mConfigDescriptors.size(); index++) {
158             configs[index] = mConfigDescriptors.get(index).toAndroid(parser);
159         }
160         UsbDevice.Builder device = new UsbDevice.Builder(parser.getDeviceAddr(), mVendorID,
161                 mProductID, mDevClass, mDevSubClass, mProtocol, mfgName, prodName, versionString,
162                 configs, serialStr);
163 
164         return device;
165     }
166 
167     @Override
parseRawDescriptors(ByteStream stream)168     public int parseRawDescriptors(ByteStream stream) {
169         mSpec = stream.unpackUsbShort();
170         mDevClass = stream.getUnsignedByte();
171         mDevSubClass = stream.getUnsignedByte();
172         mProtocol = stream.getUnsignedByte();
173         mPacketSize = stream.getByte();
174         mVendorID = stream.unpackUsbShort();
175         mProductID = stream.unpackUsbShort();
176         mDeviceRelease = stream.unpackUsbShort();
177         mMfgIndex = stream.getByte();
178         mProductIndex = stream.getByte();
179         mSerialIndex = stream.getByte();
180         mNumConfigs = stream.getByte();
181 
182         return mLength;
183     }
184 
185     @Override
report(ReportCanvas canvas)186     public void report(ReportCanvas canvas) {
187         super.report(canvas);
188 
189         canvas.openList();
190 
191         int spec = getSpec();
192         canvas.writeListItem("Spec: " + ReportCanvas.getBCDString(spec));
193 
194         int devClass = getDevClass();
195         String classStr = UsbStrings.getClassName(devClass);
196         int devSubClass = getDevSubClass();
197         String subClasStr = UsbStrings.getClassName(devSubClass);
198         canvas.writeListItem("Class " + devClass + ": " + classStr + " Subclass"
199                 + devSubClass + ": " + subClasStr);
200         canvas.writeListItem("Vendor ID: " + ReportCanvas.getHexString(getVendorID())
201                 + " Product ID: " + ReportCanvas.getHexString(getProductID())
202                 + " Product Release: " + ReportCanvas.getBCDString(getDeviceRelease()));
203 
204         UsbDescriptorParser parser = canvas.getParser();
205         byte mfgIndex = getMfgIndex();
206         String manufacturer = parser.getDescriptorString(mfgIndex);
207         byte productIndex = getProductIndex();
208         String product = parser.getDescriptorString(productIndex);
209 
210         canvas.writeListItem("Manufacturer " + mfgIndex + ": " + manufacturer
211                 + " Product " + productIndex + ": " + product);
212         canvas.closeList();
213     }
214 }
215