summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jungshik Jang <jayjang@google.com> 2014-04-30 14:31:02 +0900
committer Jungshik Jang <jayjang@google.com> 2014-05-02 10:50:08 +0900
commit3f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8 (patch)
treeae78bf2ad38d7782e86c6e49510a7945e504b129
parent8822d4befdb30452ad4276b42d89062938b51a1f (diff)
Implement logical address allocation logic for HDMI CEC.
Logical address in CEC is to distinguish each logical device from others. In order to allocate logical address for new device, CEC sends <Polling Message> to CEC bus. <Polling Message> is a CEC message which has the same address for both source and destination without body frame. (10bits). CEC allows one and more logical address for a device type. For example, there are 3 logical address defined for recorder device(1, 2, 9). Among logical address candidates for the given device type, CEC scans first the previous logical address (preferred logical address) of device. If a device has not been allocated any logical address, preferred address will be 15 (Unregistered), which means scan address from the minimum address number of type. For example for recorder device, it starts from 1. If no devices acks to the <Polling Message> during scan, it will be the logical address of the device. Since logical address is determined by a series of sending <Polling Message> it happens in IO thread with separate allocate logical address message instead of individual sendCommand message. Along with this, updated ADDR_FREE_USE(14) to ADDR_SPECIFIC_USE(14) which is revised name on HDMI 1.4. Change-Id: Ic96dcdbe4aaa3789cfed0352a88ca75369335a98
-rw-r--r--api/current.txt2
-rw-r--r--core/java/android/hardware/hdmi/HdmiCec.java8
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecController.java105
3 files changed, 110 insertions, 5 deletions
diff --git a/api/current.txt b/api/current.txt
index 4bfbec8c582f..71dc9f6c2314 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12287,7 +12287,6 @@ package android.hardware.hdmi {
method public static boolean isValidType(int);
field public static final int ADDR_AUDIO_SYSTEM = 5; // 0x5
field public static final int ADDR_BROADCAST = 15; // 0xf
- field public static final int ADDR_FREE_USE = 14; // 0xe
field public static final int ADDR_INVALID = -1; // 0xffffffff
field public static final int ADDR_PLAYBACK_1 = 4; // 0x4
field public static final int ADDR_PLAYBACK_2 = 8; // 0x8
@@ -12297,6 +12296,7 @@ package android.hardware.hdmi {
field public static final int ADDR_RECORDER_3 = 9; // 0x9
field public static final int ADDR_RESERVED_1 = 12; // 0xc
field public static final int ADDR_RESERVED_2 = 13; // 0xd
+ field public static final int ADDR_SPECIFIC_USE = 14; // 0xe
field public static final int ADDR_TUNER_1 = 3; // 0x3
field public static final int ADDR_TUNER_2 = 6; // 0x6
field public static final int ADDR_TUNER_3 = 7; // 0x7
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index 8578a320b2f0..eafaed67ba03 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -85,7 +85,7 @@ public final class HdmiCec {
public static final int ADDR_RESERVED_2 = 13;
/** Logical address for TV other than the one assigned with {@link #ADDR_TV} */
- public static final int ADDR_FREE_USE = 14;
+ public static final int ADDR_SPECIFIC_USE = 14;
/** Logical address for devices to which address cannot be allocated */
public static final int ADDR_UNREGISTERED = 15;
@@ -179,6 +179,7 @@ public final class HdmiCec {
DEVICE_RECORDER, // ADDR_RECORDER_3
DEVICE_TUNER, // ADDR_TUNER_4
DEVICE_PLAYBACK, // ADDR_PLAYBACK_3
+ DEVICE_TV, // ADDR_SPECIFIC_USE
};
private static final String[] DEFAULT_NAMES = {
@@ -194,6 +195,7 @@ public final class HdmiCec {
"Recorder_3",
"Tuner_4",
"Playback_3",
+ "Secondary_TV",
};
private HdmiCec() { } // Prevents instantiation.
@@ -221,9 +223,7 @@ public final class HdmiCec {
* @return true if the given address is valid
*/
public static boolean isValidAddress(int address) {
- // TODO: We leave out the address 'free use(14)' for now. Check this later
- // again to make sure it is a valid address for communication.
- return (ADDR_TV <= address && address <= ADDR_PLAYBACK_3);
+ return (ADDR_TV <= address && address <= ADDR_SPECIFIC_USE);
}
/**
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index f42c212281f2..c87fc99807f5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -25,6 +25,8 @@ import android.os.Message;
import android.util.Slog;
import android.util.SparseArray;
+import libcore.util.EmptyArray;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -41,11 +43,17 @@ import java.util.List;
class HdmiCecController {
private static final String TAG = "HdmiCecController";
+ private static final byte[] EMPTY_BODY = EmptyArray.BYTE;
+
// A message to pass cec send command to IO looper.
private static final int MSG_SEND_CEC_COMMAND = 1;
+ // A message to delegate logical allocation to IO looper.
+ private static final int MSG_ALLOCATE_LOGICAL_ADDRESS = 2;
// Message types to handle incoming message in main service looper.
private final static int MSG_RECEIVE_CEC_COMMAND = 1;
+ // A message to report allocated logical address to main control looper.
+ private final static int MSG_REPORT_LOGICAL_ADDRESS = 2;
// TODO: move these values to HdmiCec.java once make it internal constant class.
// CEC's ABORT reason values.
@@ -56,6 +64,11 @@ class HdmiCecController {
private static final int ABORT_REFUSED = 4;
private static final int ABORT_UNABLE_TO_DETERMINE = 5;
+ private static final int NUM_LOGICAL_ADDRESS = 16;
+
+ // TODO: define other constants for errors.
+ private static final int ERROR_SUCCESS = 0;
+
// Handler instance to process synchronous I/O (mainly send) message.
private Handler mIoHandler;
@@ -98,6 +111,43 @@ class HdmiCecController {
return handler;
}
+ /**
+ * Interface to report allocated logical address.
+ */
+ interface AllocateLogicalAddressCallback {
+ /**
+ * Called when a new logical address is allocated.
+ *
+ * @param deviceType requested device type to allocate logical address
+ * @param logicalAddress allocated logical address. If it is
+ * {@link HdmiCec#ADDR_UNREGISTERED}, it means that
+ * it failed to allocate logical address for the given device type
+ */
+ void onAllocated(int deviceType, int logicalAddress);
+ }
+
+ /**
+ * Allocate a new logical address of the given device type. Allocated
+ * address will be reported through {@link AllocateLogicalAddressCallback}.
+ *
+ * <p> Declared as package-private, accessed by {@link HdmiControlService} only.
+ *
+ * @param deviceType type of device to used to determine logical address
+ * @param preferredAddress a logical address preferred to be allocated.
+ * If sets {@link HdmiCec#ADDR_UNREGISTERED}, scans
+ * the smallest logical address matched with the given device type.
+ * Otherwise, scan address will start from {@code preferredAddress}
+ * @param callback callback interface to report allocated logical address to caller
+ */
+ void allocateLogicalAddress(int deviceType, int preferredAddress,
+ AllocateLogicalAddressCallback callback) {
+ Message msg = mIoHandler.obtainMessage(MSG_ALLOCATE_LOGICAL_ADDRESS);
+ msg.arg1 = deviceType;
+ msg.arg2 = preferredAddress;
+ msg.obj = callback;
+ mIoHandler.sendMessage(msg);
+ }
+
private static byte[] buildBody(int opcode, byte[] params) {
byte[] body = new byte[params.length + 1];
body[0] = (byte) opcode;
@@ -119,11 +169,59 @@ class HdmiCecController {
nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
cecMessage.getDestination(), body);
break;
+ case MSG_ALLOCATE_LOGICAL_ADDRESS:
+ int deviceType = msg.arg1;
+ int preferredAddress = msg.arg2;
+ AllocateLogicalAddressCallback callback =
+ (AllocateLogicalAddressCallback) msg.obj;
+ handleAllocateLogicalAddress(deviceType, preferredAddress, callback);
+ break;
default:
Slog.w(TAG, "Unsupported CEC Io request:" + msg.what);
break;
}
}
+
+ private void handleAllocateLogicalAddress(int deviceType, int preferredAddress,
+ AllocateLogicalAddressCallback callback) {
+ int startAddress = preferredAddress;
+ // If preferred address is "unregistered", start_index will be the smallest
+ // address matched with the given device type.
+ if (preferredAddress == HdmiCec.ADDR_UNREGISTERED) {
+ for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
+ if (deviceType == HdmiCec.getTypeFromAddress(i)) {
+ startAddress = i;
+ break;
+ }
+ }
+ }
+
+ int logcialAddress = HdmiCec.ADDR_UNREGISTERED;
+ // Iterates all possible addresses which has the same device type.
+ for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
+ int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
+ if (curAddress != HdmiCec.ADDR_UNREGISTERED
+ && deviceType == HdmiCec.getTypeFromAddress(i)) {
+ // <Polling Message> is a message which has empty body and
+ // uses same address for both source and destination address.
+ // If sending <Polling Message> failed (NAK), it becomes
+ // new logical address for the device because no device uses
+ // it as logical address of the device.
+ int error = nativeSendCecCommand(mNativePtr, curAddress, curAddress,
+ EMPTY_BODY);
+ if (error != ERROR_SUCCESS) {
+ logcialAddress = curAddress;
+ break;
+ }
+ }
+ }
+
+ Message msg = mControlHandler.obtainMessage(MSG_REPORT_LOGICAL_ADDRESS);
+ msg.arg1 = deviceType;
+ msg.arg2 = logcialAddress;
+ msg.obj = callback;
+ mControlHandler.sendMessage(msg);
+ }
}
private final class ControlHandler extends Handler {
@@ -138,6 +236,13 @@ class HdmiCecController {
// TODO: delegate it to HdmiControl service.
onReceiveCommand((HdmiCecMessage) msg.obj);
break;
+ case MSG_REPORT_LOGICAL_ADDRESS:
+ int deviceType = msg.arg1;
+ int logicalAddress = msg.arg2;
+ AllocateLogicalAddressCallback callback =
+ (AllocateLogicalAddressCallback) msg.obj;
+ callback.onAllocated(deviceType, logicalAddress);
+ break;
default:
Slog.i(TAG, "Unsupported message type:" + msg.what);
break;