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.UsbEndpoint;
19 import android.util.Log;
20 
21 import com.android.server.usb.descriptors.report.ReportCanvas;
22 
23 /**
24  * @hide
25  * A Usb Endpoint Descriptor.
26  * see usb11.pdf section 9.6.4
27  */
28 public class UsbEndpointDescriptor extends UsbDescriptor {
29     private static final String TAG = "UsbEndpointDescriptor";
30 
31     public static final int MASK_ENDPOINT_ADDRESS = 0b000000000001111;
32     public static final int MASK_ENDPOINT_DIRECTION = (byte) 0b0000000010000000;
33     public static final int DIRECTION_OUTPUT = 0x0000;
34     public static final int DIRECTION_INPUT = 0x0080;
35 
36     public static final int MASK_ATTRIBS_TRANSTYPE = 0b00000011;
37     public static final int TRANSTYPE_CONTROL = 0x00;
38     public static final int TRANSTYPE_ISO = 0x01;
39     public static final int TRANSTYPE_BULK = 0x02;
40     public static final int TRANSTYPE_INTERRUPT = 0x03;
41 
42     public static final byte MASK_ATTRIBS_SYNCTYPE = 0b00001100;
43     public static final byte SYNCTYPE_NONE = 0b00000000;
44     public static final byte SYNCTYPE_ASYNC = 0b00000100;
45     public static final byte SYNCTYPE_ADAPTSYNC = 0b00001000;
46     public static final byte SYNCTYPE_RESERVED = 0b00001100;
47 
48     public static final int MASK_ATTRIBS_USEAGE = 0b00110000;
49     public static final int USEAGE_DATA = 0b00000000;
50     public static final int USEAGE_FEEDBACK = 0b00010000;
51     public static final int USEAGE_EXPLICIT = 0b00100000;
52     public static final int USEAGE_RESERVED = 0b00110000;
53 
54     private int mEndpointAddress;   // 2:1 Endpoint Address
55                                     // Bits 0..3b Endpoint Number.
56                                     // Bits 4..6b Reserved. Set to Zero
57                                     // Bits 7 Direction 0 = Out, 1 = In
58                                     // (Ignored for Control Endpoints)
59     private int mAttributes;    // 3:1 Various flags
60                                 // Bits 0..1 Transfer Type:
61                                 //     00 = Control, 01 = Isochronous, 10 = Bulk, 11 = Interrupt
62                                 // Bits 2..7 are reserved. If Isochronous endpoint,
63                                 // Bits 3..2 = Synchronisation Type (Iso Mode)
64                                 //  00 = No Synchonisation
65                                 //  01 = Asynchronous
66                                 //  10 = Adaptive
67                                 //  11 = Synchronous
68                                 // Bits 5..4 = Usage Type (Iso Mode)
69                                 //  00: Data Endpoint
70                                 //  01:Feedback Endpoint 10
71                                 //  Explicit Feedback Data Endpoint
72                                 //  11: Reserved
73     private int mPacketSize;    // 4:2 Maximum Packet Size this endpoint is capable of
74                                 // sending or receiving
75     private int mInterval;      // 6:1 Interval for polling endpoint data transfers. Value in
76                                 // frame counts.
77                                 // Ignored for Bulk & Control Endpoints. Isochronous must equal
78                                 // 1 and field may range from 1 to 255 for interrupt endpoints.
79     private byte mRefresh;
80     private byte mSyncAddress;
81 
82     private UsbDescriptor mClassSpecificEndpointDescriptor;
83 
UsbEndpointDescriptor(int length, byte type)84     public UsbEndpointDescriptor(int length, byte type) {
85         super(length, type);
86         mHierarchyLevel = 4;
87     }
88 
getEndpointAddress()89     public int getEndpointAddress() {
90         return mEndpointAddress & MASK_ENDPOINT_ADDRESS;
91     }
92 
getAttributes()93     public int getAttributes() {
94         return mAttributes;
95     }
96 
getPacketSize()97     public int getPacketSize() {
98         return mPacketSize;
99     }
100 
getInterval()101     public int getInterval() {
102         return mInterval;
103     }
104 
getRefresh()105     public byte getRefresh() {
106         return mRefresh;
107     }
108 
getSyncAddress()109     public byte getSyncAddress() {
110         return mSyncAddress;
111     }
112 
getDirection()113     public int getDirection() {
114         return mEndpointAddress & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION;
115     }
116 
setClassSpecificEndpointDescriptor(UsbDescriptor descriptor)117     void setClassSpecificEndpointDescriptor(UsbDescriptor descriptor) {
118         mClassSpecificEndpointDescriptor = descriptor;
119     }
120 
getClassSpecificEndpointDescriptor()121     public UsbDescriptor getClassSpecificEndpointDescriptor() {
122         return mClassSpecificEndpointDescriptor;
123     }
124 
125     /**
126     * Returns a UsbEndpoint that this UsbEndpointDescriptor is describing.
127     */
toAndroid(UsbDescriptorParser parser)128     public UsbEndpoint toAndroid(UsbDescriptorParser parser) {
129         if (UsbDescriptorParser.DEBUG) {
130             Log.d(TAG, "toAndroid() type:"
131                     + Integer.toHexString(mAttributes & MASK_ATTRIBS_TRANSTYPE)
132                     + " sync:" + Integer.toHexString(mAttributes & MASK_ATTRIBS_SYNCTYPE)
133                     + " usage:" + Integer.toHexString(mAttributes & MASK_ATTRIBS_USEAGE));
134         }
135         return new UsbEndpoint(mEndpointAddress, mAttributes, mPacketSize, mInterval);
136     }
137 
138     @Override
parseRawDescriptors(ByteStream stream)139     public int parseRawDescriptors(ByteStream stream) {
140         mEndpointAddress = stream.getUnsignedByte();
141         mAttributes = stream.getUnsignedByte();
142         mPacketSize = stream.unpackUsbShort();
143         mInterval = stream.getUnsignedByte();
144         if (mLength == 9) {
145             mRefresh = stream.getByte();
146             mSyncAddress = stream.getByte();
147         }
148         return mLength;
149     }
150 
151     @Override
report(ReportCanvas canvas)152     public void report(ReportCanvas canvas) {
153         super.report(canvas);
154 
155         canvas.openList();
156 
157         canvas.writeListItem("Address: "
158                 + ReportCanvas.getHexString(getEndpointAddress())
159                 + (getDirection() == UsbEndpointDescriptor.DIRECTION_OUTPUT ? " [out]" : " [in]"));
160 
161         int attributes = getAttributes();
162         canvas.openListItem();
163         canvas.write("Attributes: " + ReportCanvas.getHexString(attributes) + " ");
164         switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE) {
165             case UsbEndpointDescriptor.TRANSTYPE_CONTROL:
166                 canvas.write("Control");
167                 break;
168             case UsbEndpointDescriptor.TRANSTYPE_ISO:
169                 canvas.write("Iso");
170                 break;
171             case UsbEndpointDescriptor.TRANSTYPE_BULK:
172                 canvas.write("Bulk");
173                 break;
174             case UsbEndpointDescriptor.TRANSTYPE_INTERRUPT:
175                 canvas.write("Interrupt");
176                 break;
177         }
178         canvas.closeListItem();
179 
180         // These flags are only relevant for ISO transfer type
181         if ((attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE)
182                 == UsbEndpointDescriptor.TRANSTYPE_ISO) {
183             canvas.openListItem();
184             canvas.write("Aync: ");
185             switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_SYNCTYPE) {
186                 case UsbEndpointDescriptor.SYNCTYPE_NONE:
187                     canvas.write("NONE");
188                     break;
189                 case UsbEndpointDescriptor.SYNCTYPE_ASYNC:
190                     canvas.write("ASYNC");
191                     break;
192                 case UsbEndpointDescriptor.SYNCTYPE_ADAPTSYNC:
193                     canvas.write("ADAPTIVE ASYNC");
194                     break;
195             }
196             canvas.closeListItem();
197 
198             canvas.openListItem();
199             canvas.write("Useage: ");
200             switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_USEAGE) {
201                 case UsbEndpointDescriptor.USEAGE_DATA:
202                     canvas.write("DATA");
203                     break;
204                 case UsbEndpointDescriptor.USEAGE_FEEDBACK:
205                     canvas.write("FEEDBACK");
206                     break;
207                 case UsbEndpointDescriptor.USEAGE_EXPLICIT:
208                     canvas.write("EXPLICIT FEEDBACK");
209                     break;
210                 case UsbEndpointDescriptor.USEAGE_RESERVED:
211                     canvas.write("RESERVED");
212                     break;
213             }
214             canvas.closeListItem();
215         }
216         canvas.writeListItem("Package Size: " + getPacketSize());
217         canvas.writeListItem("Interval: " + getInterval());
218         canvas.closeList();
219     }
220 }
221