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 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         UsbDevice device = new UsbDevice(parser.getDeviceAddr(), mVendorID, mProductID,
156                 mDevClass, mDevSubClass,
157                 mProtocol, mfgName, prodName,
158                 versionString, serialStr);
159         UsbConfiguration[] configs = new UsbConfiguration[mConfigDescriptors.size()];
160         Log.d(TAG, "  " + configs.length + " configs");
161         for (int index = 0; index < mConfigDescriptors.size(); index++) {
162             configs[index] = mConfigDescriptors.get(index).toAndroid(parser);
163         }
164         device.setConfigurations(configs);
165 
166         return device;
167     }
168 
169     @Override
parseRawDescriptors(ByteStream stream)170     public int parseRawDescriptors(ByteStream stream) {
171         mSpec = stream.unpackUsbShort();
172         mDevClass = stream.getUnsignedByte();
173         mDevSubClass = stream.getUnsignedByte();
174         mProtocol = stream.getUnsignedByte();
175         mPacketSize = stream.getByte();
176         mVendorID = stream.unpackUsbShort();
177         mProductID = stream.unpackUsbShort();
178         mDeviceRelease = stream.unpackUsbShort();
179         mMfgIndex = stream.getByte();
180         mProductIndex = stream.getByte();
181         mSerialIndex = stream.getByte();
182         mNumConfigs = stream.getByte();
183 
184         return mLength;
185     }
186 
187     @Override
report(ReportCanvas canvas)188     public void report(ReportCanvas canvas) {
189         super.report(canvas);
190 
191         canvas.openList();
192 
193         int spec = getSpec();
194         canvas.writeListItem("Spec: " + ReportCanvas.getBCDString(spec));
195 
196         int devClass = getDevClass();
197         String classStr = UsbStrings.getClassName(devClass);
198         int devSubClass = getDevSubClass();
199         String subClasStr = UsbStrings.getClassName(devSubClass);
200         canvas.writeListItem("Class " + devClass + ": " + classStr + " Subclass"
201                 + devSubClass + ": " + subClasStr);
202         canvas.writeListItem("Vendor ID: " + ReportCanvas.getHexString(getVendorID())
203                 + " Product ID: " + ReportCanvas.getHexString(getProductID())
204                 + " Product Release: " + ReportCanvas.getBCDString(getDeviceRelease()));
205 
206         UsbDescriptorParser parser = canvas.getParser();
207         byte mfgIndex = getMfgIndex();
208         String manufacturer = parser.getDescriptorString(mfgIndex);
209         byte productIndex = getProductIndex();
210         String product = parser.getDescriptorString(productIndex);
211 
212         canvas.writeListItem("Manufacturer " + mfgIndex + ": " + manufacturer
213                 + " Product " + productIndex + ": " + product);
214         canvas.closeList();
215     }
216 }
217