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 
35     public static final int USBSPEC_1_0 = 0x0100;
36     public static final int USBSPEC_1_1 = 0x0110;
37     public static final int USBSPEC_2_0 = 0x0200;
38 
39     private int mSpec;          // 2:2 bcdUSB 2 BCD USB Specification Number - BCD
40     private int mDevClass;      // 4:1 class code
41     private int mDevSubClass;   // 5:1 subclass code
42     private int mProtocol;      // 6:1 protocol
43     private byte mPacketSize;   // 7:1 Maximum Packet Size for Zero Endpoint.
44                                 // Valid Sizes are 8, 16, 32, 64
45     private int mVendorID;      // 8:2 vendor ID
46     private int mProductID;     // 10:2 product ID
47     private int mDeviceRelease; // 12:2 Device Release number - BCD
48     private byte mMfgIndex;     // 14:1 Index of Manufacturer String Descriptor
49     private byte mProductIndex; // 15:1 Index of Product String Descriptor
50     private byte mSerialIndex;  // 16:1 Index of Serial Number String Descriptor
51     private byte mNumConfigs;   // 17:1 Number of Possible Configurations
52 
53     private ArrayList<UsbConfigDescriptor> mConfigDescriptors =
54             new ArrayList<UsbConfigDescriptor>();
55 
UsbDeviceDescriptor(int length, byte type)56     UsbDeviceDescriptor(int length, byte type) {
57         super(length, type);
58         mHierarchyLevel = 1;
59     }
60 
getSpec()61     public int getSpec() {
62         return mSpec;
63     }
64 
getDevClass()65     public int getDevClass() {
66         return mDevClass;
67     }
68 
getDevSubClass()69     public int getDevSubClass() {
70         return mDevSubClass;
71     }
72 
getProtocol()73     public int getProtocol() {
74         return mProtocol;
75     }
76 
getPacketSize()77     public byte getPacketSize() {
78         return mPacketSize;
79     }
80 
getVendorID()81     public int getVendorID() {
82         return mVendorID;
83     }
84 
getProductID()85     public int getProductID() {
86         return mProductID;
87     }
88 
getDeviceRelease()89     public int getDeviceRelease() {
90         return mDeviceRelease;
91     }
92 
93     // mDeviceRelease is binary-coded decimal, format DD.DD
getDeviceReleaseString()94     public String getDeviceReleaseString() {
95         int hundredths = mDeviceRelease & 0xF;
96         int tenths = (mDeviceRelease & 0xF0) >> 4;
97         int ones = (mDeviceRelease & 0xF00) >> 8;
98         int tens = (mDeviceRelease & 0xF000) >> 12;
99         return String.format("%d.%d%d", tens * 10 + ones, tenths, hundredths);
100     }
101 
getMfgIndex()102     public byte getMfgIndex() {
103         return mMfgIndex;
104     }
105 
getMfgString(UsbDescriptorParser p)106     public String getMfgString(UsbDescriptorParser p) {
107         return p.getDescriptorString(mMfgIndex);
108     }
109 
getProductIndex()110     public byte getProductIndex() {
111         return mProductIndex;
112     }
113 
getProductString(UsbDescriptorParser p)114     public String getProductString(UsbDescriptorParser p) {
115         return p.getDescriptorString(mProductIndex);
116     }
117 
getSerialIndex()118     public byte getSerialIndex() {
119         return mSerialIndex;
120     }
121 
getSerialString(UsbDescriptorParser p)122     public String getSerialString(UsbDescriptorParser p) {
123         return p.getDescriptorString(mSerialIndex);
124     }
125 
getNumConfigs()126     public byte getNumConfigs() {
127         return mNumConfigs;
128     }
129 
addConfigDescriptor(UsbConfigDescriptor config)130     void addConfigDescriptor(UsbConfigDescriptor config) {
131         mConfigDescriptors.add(config);
132     }
133 
134     /**
135      * @hide
136      */
toAndroid(UsbDescriptorParser parser)137     public UsbDevice.Builder toAndroid(UsbDescriptorParser parser) {
138         if (UsbDescriptorParser.DEBUG) {
139             Log.d(TAG, "toAndroid()");
140         }
141 
142         String mfgName = getMfgString(parser);
143         String prodName = getProductString(parser);
144         if (UsbDescriptorParser.DEBUG) {
145             Log.d(TAG, "  mfgName:" + mfgName + " prodName:" + prodName);
146         }
147 
148         String versionString = getDeviceReleaseString();
149         String serialStr = getSerialString(parser);
150         if (UsbDescriptorParser.DEBUG) {
151             Log.d(TAG, "  versionString:" + versionString + " serialStr:" + serialStr);
152         }
153 
154         UsbConfiguration[] configs = new UsbConfiguration[mConfigDescriptors.size()];
155         Log.d(TAG, "  " + configs.length + " configs");
156         for (int index = 0; index < mConfigDescriptors.size(); index++) {
157             configs[index] = mConfigDescriptors.get(index).toAndroid(parser);
158         }
159 
160         return new UsbDevice.Builder(parser.getDeviceAddr(), mVendorID,
161                 mProductID, mDevClass, mDevSubClass, mProtocol, mfgName, prodName, versionString,
162                 configs, serialStr, parser.hasAudioPlayback(), parser.hasAudioCapture(),
163                 parser.hasMIDIInterface(),
164                 parser.hasVideoPlayback(), parser.hasVideoCapture());
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