1 /* 2 * Copyright (C) 2018 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 17 package android.hardware.hdmi; 18 19 import android.annotation.IntDef; 20 21 import java.lang.annotation.Retention; 22 import java.lang.annotation.RetentionPolicy; 23 24 /** 25 * Various utilities related to HDMI CEC. 26 * 27 * TODO(b/110094868): unhide for Q 28 * @hide 29 */ 30 public final class HdmiUtils { 31 /** 32 * Return value of {@link #getLocalPortFromPhysicalAddress(int, int)} 33 */ 34 static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1; 35 static final int TARGET_SAME_PHYSICAL_ADDRESS = 0; 36 HdmiUtils()37 private HdmiUtils() { /* cannot be instantiated */ } 38 39 /** 40 * Method to parse target physical address to the port number on the current device. 41 * 42 * <p>This check assumes target address is valid. 43 * 44 * @param targetPhysicalAddress is the physical address of the target device 45 * @param myPhysicalAddress is the physical address of the current device 46 * @return 47 * If the target device is under the current device, return the port number of current device 48 * that the target device is connected to. This also applies to the devices that are indirectly 49 * connected to the current device. 50 * 51 * <p>If the target device has the same physical address as the current device, return 52 * {@link #TARGET_SAME_PHYSICAL_ADDRESS}. 53 * 54 * <p>If the target device is not under the current device, return 55 * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}. 56 */ getLocalPortFromPhysicalAddress( int targetPhysicalAddress, int myPhysicalAddress)57 public static int getLocalPortFromPhysicalAddress( 58 int targetPhysicalAddress, int myPhysicalAddress) { 59 if (myPhysicalAddress == targetPhysicalAddress) { 60 return TARGET_SAME_PHYSICAL_ADDRESS; 61 } 62 63 int mask = 0xF000; 64 int finalMask = 0xF000; 65 int maskedAddress = myPhysicalAddress; 66 67 while (maskedAddress != 0) { 68 maskedAddress = myPhysicalAddress & mask; 69 finalMask |= mask; 70 mask >>= 4; 71 } 72 73 int portAddress = targetPhysicalAddress & finalMask; 74 if ((portAddress & (finalMask << 4)) != myPhysicalAddress) { 75 return TARGET_NOT_UNDER_LOCAL_DEVICE; 76 } 77 78 mask <<= 4; 79 int port = portAddress & mask; 80 while ((port >> 4) != 0) { 81 port >>= 4; 82 } 83 return port; 84 } 85 86 /** 87 * TODO(b/110094868): unhide for Q 88 * @hide 89 */ 90 @Retention(RetentionPolicy.SOURCE) 91 @IntDef({HDMI_RELATIVE_POSITION_UNKNOWN, HDMI_RELATIVE_POSITION_DIRECTLY_BELOW, 92 HDMI_RELATIVE_POSITION_BELOW, HDMI_RELATIVE_POSITION_SAME, 93 HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE, HDMI_RELATIVE_POSITION_ABOVE, 94 HDMI_RELATIVE_POSITION_SIBLING, HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH}) 95 public @interface HdmiAddressRelativePosition {} 96 /** 97 * HDMI relative position is not determined. 98 * TODO(b/110094868): unhide for Q 99 * @hide 100 */ 101 public static final int HDMI_RELATIVE_POSITION_UNKNOWN = 0; 102 /** 103 * HDMI relative position: directly blow the device. 104 * TODO(b/110094868): unhide for Q 105 * @hide 106 */ 107 public static final int HDMI_RELATIVE_POSITION_DIRECTLY_BELOW = 1; 108 /** 109 * HDMI relative position: indirectly below the device. 110 * TODO(b/110094868): unhide for Q 111 * @hide 112 */ 113 public static final int HDMI_RELATIVE_POSITION_BELOW = 2; 114 /** 115 * HDMI relative position: the same device. 116 * TODO(b/110094868): unhide for Q 117 * @hide 118 */ 119 public static final int HDMI_RELATIVE_POSITION_SAME = 3; 120 /** 121 * HDMI relative position: directly above the device. 122 * TODO(b/110094868): unhide for Q 123 * @hide 124 */ 125 public static final int HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE = 4; 126 /** 127 * HDMI relative position: indirectly above the device. 128 * TODO(b/110094868): unhide for Q 129 * @hide 130 */ 131 public static final int HDMI_RELATIVE_POSITION_ABOVE = 5; 132 /** 133 * HDMI relative position: directly below a same device. 134 * TODO(b/110094868): unhide for Q 135 * @hide 136 */ 137 public static final int HDMI_RELATIVE_POSITION_SIBLING = 6; 138 /** 139 * HDMI relative position: different branch. 140 * TODO(b/110094868): unhide for Q 141 * @hide 142 */ 143 public static final int HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH = 7; 144 145 private static final int NPOS = -1; 146 147 /** 148 * Check if the given physical address is valid. 149 * 150 * @param address physical address 151 * @return {@code true} if the given address is valid 152 */ isValidPhysicalAddress(int address)153 public static boolean isValidPhysicalAddress(int address) { 154 if (address < 0 || address >= 0xFFFF) { 155 return false; 156 } 157 int mask = 0xF000; 158 boolean hasZero = false; 159 for (int i = 0; i < 4; i++) { 160 if ((address & mask) == 0) { 161 hasZero = true; 162 } else if (hasZero) { 163 // only 0s are valid after a 0. 164 // e.g. 0x1012 is not valid. 165 return false; 166 } 167 mask >>= 4; 168 } 169 return true; 170 } 171 172 173 /** 174 * Returns the relative position of two physical addresses. 175 */ 176 @HdmiAddressRelativePosition getHdmiAddressRelativePosition(int src, int dest)177 public static int getHdmiAddressRelativePosition(int src, int dest) { 178 if (src == 0xFFFF || dest == 0xFFFF) { 179 // address not assigned 180 return HDMI_RELATIVE_POSITION_UNKNOWN; 181 } 182 try { 183 int firstDiffPos = physicalAddressFirstDifferentDigitPos(src, dest); 184 if (firstDiffPos == NPOS) { 185 return HDMI_RELATIVE_POSITION_SAME; 186 } 187 int mask = (0xF000 >> (firstDiffPos * 4)); 188 int nextPos = firstDiffPos + 1; 189 if ((src & mask) == 0) { 190 // src is above dest 191 if (nextPos == 4) { 192 // last digits are different 193 return HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE; 194 } 195 if (((0xF000 >> (nextPos * 4)) & dest) == 0) { 196 // next digit is 0 197 return HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE; 198 } 199 return HDMI_RELATIVE_POSITION_ABOVE; 200 } 201 202 if ((dest & mask) == 0) { 203 // src is below dest 204 if (nextPos == 4) { 205 // last digits are different 206 return HDMI_RELATIVE_POSITION_DIRECTLY_BELOW; 207 } 208 if (((0xF000 >> (nextPos * 4)) & src) == 0) { 209 // next digit is 0 210 return HDMI_RELATIVE_POSITION_DIRECTLY_BELOW; 211 } 212 return HDMI_RELATIVE_POSITION_BELOW; 213 } 214 if (nextPos == 4) { 215 // last digits are different 216 return HDMI_RELATIVE_POSITION_SIBLING; 217 } 218 if (((0xF000 >> (nextPos * 4)) & src) == 0 && ((0xF000 >> (nextPos * 4)) & dest) == 0) { 219 return HDMI_RELATIVE_POSITION_SIBLING; 220 } 221 return HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH; 222 } catch (IllegalArgumentException e) { 223 // invalid address 224 return HDMI_RELATIVE_POSITION_UNKNOWN; 225 } 226 } 227 physicalAddressFirstDifferentDigitPos(int address1, int address2)228 private static int physicalAddressFirstDifferentDigitPos(int address1, int address2) 229 throws IllegalArgumentException { 230 if (!isValidPhysicalAddress(address1)) { 231 throw new IllegalArgumentException(address1 + " is not a valid address."); 232 } 233 if (!isValidPhysicalAddress(address2)) { 234 throw new IllegalArgumentException(address2 + " is not a valid address."); 235 } 236 int mask = 0xF000; 237 for (int i = 0; i < 4; i++) { 238 if ((address1 & mask) != (address2 & mask)) { 239 return i; 240 } 241 mask = mask >> 4; 242 } 243 return NPOS; 244 } 245 } 246