31 Commits

Author SHA1 Message Date
Konsta
8b85358ac8 virtualization: report vm as supported
* 8c352a4c5c
* Fixes dc1fc3a6e3.
2025-03-06 17:20:06 +02:00
Konsta
cbcaf931e3 add touchscreen permission 2025-03-06 17:19:22 +02:00
Konsta
91a626c855 libcamera: add configurations for imx519 and ov64a40 camera modules 2025-03-02 13:25:13 +02:00
Konsta
d31cd0ab1c audio: proprietary -> vendor 2025-03-02 13:25:04 +02:00
Konsta
3a141e6b33 suspend_blocker: proprietary -> vendor 2025-03-02 13:24:56 +02:00
Konsta
3c8683bd0c overlay: proprietary -> vendor 2025-03-02 13:24:44 +02:00
Konsta
51073dd508 bluetooth: enable A2DP sink
* A2DP source and sink can coexist on Android 15.
  https://android-review.googlesource.com/q/topic:%22bt_a2dp_src_sink_coexist%22
* Fixes https://github.com/raspberry-vanilla/android_local_manifest/issues/188.
2025-03-01 22:26:28 +02:00
Konsta
6c7ec173b4 mkimg: adjust flashable image size again
* Different decimal separator is used depending on the locale.
* 14848MiB = 15569256448 bytes.
* Fixes https://github.com/raspberry-vanilla/android_local_manifest/issues/187.
* Fixes e2a1429001.
2025-02-27 17:37:20 +02:00
Konsta
e2a1429001 mkimg: adjust flashable image size
* Raspberry Pi Imager expects image size to be multiple of 512 bytes
  so revert back to using gibibytes.
* 14.5GiB = 15569256448 bytes.
* Fixes c71777ecdd.

Change-Id: Iae83ff6a3eb2b6033279ac5bfcd5d952577eeefa
2025-02-25 19:57:35 +02:00
Konsta
2ff057cea4 graphics: remove libglapi from mesa packages
* No longer exists on Mesa 25.0.
2025-02-25 17:02:19 +02:00
Konsta
831688d8ae overlay: tv: remove minimum screenoff timeout
* Fixes screen saver on Android TV.
* IIRC this is an old hack when Android TV didn't respect stay awake
  option. Probably hasn't been needed in years.
2025-02-20 15:09:57 +02:00
Konsta
2f5981de4f health: fake more battery stats
Change-Id: Ic511604c9ed5e5972af34ef0afb120affacd0586
2025-02-20 15:09:17 +02:00
Konsta
c71777ecdd mkimg: increase image size to fit 16GB storage device
* This will create a flashable image that is 15500000000 bytes.
* I checked several 16GB sdcards and USB storage devices and the
  actual byte size ranged from 15646851072 to 16008609792.
2025-02-20 15:09:17 +02:00
Konsta
f0a37c0c28 mkimg: use fallocate to create the image
* This is much faster than creating a file by filling it with zeroes.
* Remove unnecessary quotes for consistency.
2025-02-20 15:09:17 +02:00
Konsta
9f38f9eece Revert "graphics: disable hwc config groups"
* Disabled by default on upstream
  cd3902ab4a.

This reverts commit 66656f14fb.
2025-02-20 15:04:49 +02:00
Konsta
eb5b8812c3 cec: check input on device property 2025-02-06 15:00:50 +02:00
Konsta
07e066812c cec: add rpi hal implementation
* TODO: Convert to AIDL.
2025-02-05 20:20:07 +02:00
Konsta
9b0ddfd25d cec: remove mock hal 2025-02-05 20:19:48 +02:00
Konsta
1b74e802ee cec: copy hidl hal
* Copy from hardware/interfaces/tv/cec/1.0/default
  at b04e2f3df5ebbbeea46f555d0965357f05aa1457.
2025-02-05 20:19:38 +02:00
Konsta
f999796b13 cec: remove legacy hal
This reverts commit c0a8378d8b and more.
2025-02-05 20:18:33 +02:00
Konsta
822083ba68 overlay: disable screen dimming by default 2025-02-02 15:48:54 +02:00
Konsta
2da7253013 lights: boot: use DSI panel regulator driver
* Old rpi_backlight driver is no longer used on recent kernel versions.
  Regulator driver is used for backlight instead.
* Change the backlight path and implement scaling to support the official
  Raspberry Pi 7" DSI Touch Display & Touch Display 2.
* The original Touch Display has max brightness of 255 while the new Touch
  Display 2 has 31.
2025-02-02 15:47:10 +02:00
Konsta
1b7cb2e460 mkimg: set image owner 2025-01-30 20:01:45 +02:00
Konsta
318905d5ef mkimg: minor cleanups 2025-01-30 20:00:25 +02:00
Konsta
bc1843f1e6 mkimg: check partition images exist 2025-01-30 18:35:35 +02:00
Konsta
451f4129cd mkimg: strip aosp_ from build target 2025-01-30 18:35:25 +02:00
MinnieTheMoocher
936497eced mkimg: use existing env variables instead of hardcoded strings
* this requires to run "lunch" before, the script checks for that
2025-01-30 18:34:51 +02:00
Konsta
66656f14fb graphics: disable hwc config groups
* 613a9440a0.
2025-01-02 21:30:53 +02:00
Konsta
7bacc18602 boot: ramdisk: add CM5 USB configuration 2025-01-02 21:30:33 +02:00
Konsta
ec9011cc09 boot: increase CMA size
* CMA size was decreased in 3edaa3875f.
* Larger CMA allocation is needed for H.265 hardware decoding
  in some cases. Essentially revert the above change.

Change-Id: I7b53cc6bca4663be4a51ab61daf644460d09532d
2024-12-13 18:50:20 +02:00
Konsta
1899d4a4e4 graphics: switch to aidl allocator and gralloc5 mapper 2024-12-13 18:50:20 +02:00
43 changed files with 1058 additions and 700 deletions

View File

@@ -75,6 +75,9 @@ BOARD_VNDK_VERSION := current
PRODUCT_FULL_TREBLE_OVERRIDE := true
TARGET_COPY_OUT_VENDOR := vendor
# Virtualization
BOARD_KERNEL_CMDLINE += androidboot.hypervisor.vm.supported=1
# Wifi
BOARD_WLAN_DEVICE := bcmdhd
BOARD_HOSTAPD_DRIVER := NL80211

View File

@@ -15,8 +15,9 @@ $(call inherit-product, $(SRC_TARGET_DIR)/product/full_base.mk)
# Overlays
PRODUCT_PACKAGES += \
AndroidRpiOverlay \
SettingsRpiOverlay \
BluetoothRpiOverlay \
SettingsProviderRpiOverlay \
SettingsRpiOverlay \
SystemUIRpiOverlay \
WifiRpiOverlay

View File

@@ -84,6 +84,7 @@ include packages/services/Car/car_product/occupant_awareness/OccupantAwareness.m
# Overlays
PRODUCT_PACKAGES += \
AndroidRpiOverlay \
BluetoothRpiOverlay \
CarServiceRpiOverlay \
SettingsProviderRpiOverlay \
WifiRpiOverlay

View File

@@ -30,6 +30,7 @@ PRODUCT_COPY_FILES += \
# Overlays
PRODUCT_PACKAGES += \
AndroidTvRpiOverlay \
BluetoothRpiOverlay \
SettingsProviderTvRpiOverlay \
WifiRpiOverlay

View File

@@ -6,7 +6,7 @@
cc_library_shared {
name: "audio.primary.rpi",
relative_install_path: "hw",
proprietary: true,
vendor: true,
srcs: ["audio_hw.c"],
include_dirs: [
"external/expat/lib",
@@ -26,7 +26,7 @@ cc_library_shared {
cc_library_shared {
name: "audio.primary.rpi_hdmi",
relative_install_path: "hw",
proprietary: true,
vendor: true,
srcs: ["audio_hw_hdmi.c"],
include_dirs: [
"external/expat/lib",

View File

@@ -13,10 +13,11 @@ disable_overscan=1
# Display panel
#dtoverlay=vc4-kms-dsi-7inch
#dtoverlay=rpi-backlight
#dtoverlay=vc4-kms-dsi-ili9881-7inch
# Graphics acceleration
dtoverlay=vc4-kms-v3d
dtoverlay=cma,cma-320
# I2C
#dtparam=i2c_arm=on
@@ -29,3 +30,6 @@ dtoverlay=vc4-kms-v3d
# USB
dtoverlay=dwc2,dr_mode=peripheral
[cm5]
dtoverlay=dwc2,dr_mode=otg
[all]

View File

@@ -11,9 +11,15 @@ cameras:
"/base/axi/pcie@120000/rp1/i2c@88000/imx500@1a":
location: back
rotation: 0
"/base/axi/pcie@120000/rp1/i2c@88000/imx519@1a":
location: back
rotation: 0
"/base/axi/pcie@120000/rp1/i2c@88000/imx708@1a":
location: back
rotation: 0
"/base/axi/pcie@120000/rp1/i2c@88000/ov5647@36":
location: back
rotation: 0
"/base/axi/pcie@120000/rp1/i2c@88000/ov64a40@36":
location: back
rotation: 0

View File

@@ -1,17 +1,26 @@
// Copyright (C) 2019 The Android Open-Source Project
// Copyright (C) 2021-2022 KonstaKANG
// Copyright (C) 2021 The Android Open Source Project
// Copyright (C) 2025 KonstaKANG
//
// SPDX-License-Identifier: Apache-2.0
cc_library_shared {
name: "hdmi_cec.rpi",
cc_binary {
name: "android.hardware.tv.cec@1.0-service.rpi",
relative_install_path: "hw",
proprietary: true,
srcs: ["hdmi_cec.c"],
cflags: ["-Werror"],
init_rc: ["android.hardware.tv.cec@1.0-service.rpi.rc"],
vintf_fragments: ["android.hardware.tv.cec@1.0-service.rpi.xml"],
vendor: true,
srcs: [
"HdmiCec.cpp",
"HdmiCecPort.cpp",
"service.cpp",
],
shared_libs: [
"liblog",
"android.hardware.tv.cec@1.0",
"libbase",
"libcutils",
"libhardware",
"libhidlbase",
"liblog",
"libutils",
],
}

504
cec/HdmiCec.cpp Normal file
View File

@@ -0,0 +1,504 @@
/*
* Copyright (C) 2021 The Android Open Source Project
* Copyright (C) 2025 KonstaKANG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.tv.cec@1.0-service.rpi"
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <cutils/properties.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#include <poll.h>
#include "HdmiCec.h"
#define PROPERTY_CEC_DEVICE "persist.hdmi.cec_device"
#define PROPERTY_CEC_VERSION "ro.hdmi.cec_version"
#define PROPERTY_VENDOR_ID "ro.hdmi.vendor_id"
namespace android {
namespace hardware {
namespace tv {
namespace cec {
namespace V1_0 {
namespace implementation {
using android::base::GetProperty;
using std::string;
HdmiCec::HdmiCec() {
mCecEnabled = false;
mWakeupEnabled = false;
mCecControlEnabled = false;
mCallback = nullptr;
Result result = init();
if (result != Result::SUCCESS) {
LOG(ERROR) << "Failed to init HDMI-CEC HAL";
}
}
HdmiCec::~HdmiCec() {
release();
}
// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
Return<Result> HdmiCec::addLogicalAddress(CecLogicalAddress addr) {
if (addr < CecLogicalAddress::TV || addr >= CecLogicalAddress::BROADCAST) {
LOG(ERROR) << "Add logical address failed, Invalid address";
return Result::FAILURE_INVALID_ARGS;
}
cec_log_addrs cecLogAddrs;
int ret = ioctl(mHdmiCecPorts[0]->mCecFd, CEC_ADAP_G_LOG_ADDRS, &cecLogAddrs);
if (ret) {
LOG(ERROR) << "Add logical address failed, Error = " << strerror(errno);
return Result::FAILURE_BUSY;
}
cecLogAddrs.cec_version = getCecVersion();
cecLogAddrs.vendor_id = getVendorId();
unsigned int logAddrType = CEC_LOG_ADDR_TYPE_UNREGISTERED;
unsigned int allDevTypes = 0;
unsigned int primDevType = 0xff;
switch (addr) {
case CecLogicalAddress::TV:
primDevType = CEC_OP_PRIM_DEVTYPE_TV;
logAddrType = CEC_LOG_ADDR_TYPE_TV;
allDevTypes = CEC_OP_ALL_DEVTYPE_TV;
break;
case CecLogicalAddress::RECORDER_1:
case CecLogicalAddress::RECORDER_2:
case CecLogicalAddress::RECORDER_3:
primDevType = CEC_OP_PRIM_DEVTYPE_RECORD;
logAddrType = CEC_LOG_ADDR_TYPE_RECORD;
allDevTypes = CEC_OP_ALL_DEVTYPE_RECORD;
break;
case CecLogicalAddress::TUNER_1:
case CecLogicalAddress::TUNER_2:
case CecLogicalAddress::TUNER_3:
case CecLogicalAddress::TUNER_4:
primDevType = CEC_OP_PRIM_DEVTYPE_TUNER;
logAddrType = CEC_LOG_ADDR_TYPE_TUNER;
allDevTypes = CEC_OP_ALL_DEVTYPE_TUNER;
break;
case CecLogicalAddress::PLAYBACK_1:
case CecLogicalAddress::PLAYBACK_2:
case CecLogicalAddress::PLAYBACK_3:
primDevType = CEC_OP_PRIM_DEVTYPE_PLAYBACK;
logAddrType = CEC_LOG_ADDR_TYPE_PLAYBACK;
allDevTypes = CEC_OP_ALL_DEVTYPE_PLAYBACK;
cecLogAddrs.flags |= CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU;
break;
case CecLogicalAddress::AUDIO_SYSTEM:
primDevType = CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM;
logAddrType = CEC_LOG_ADDR_TYPE_AUDIOSYSTEM;
allDevTypes = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM;
break;
case CecLogicalAddress::FREE_USE:
primDevType = CEC_OP_PRIM_DEVTYPE_PROCESSOR;
logAddrType = CEC_LOG_ADDR_TYPE_SPECIFIC;
allDevTypes = CEC_OP_ALL_DEVTYPE_SWITCH;
break;
case CecLogicalAddress::UNREGISTERED:
cecLogAddrs.flags |= CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK;
break;
}
int logAddrIndex = cecLogAddrs.num_log_addrs;
cecLogAddrs.num_log_addrs += 1;
cecLogAddrs.log_addr[logAddrIndex] = static_cast<cec_logical_address_t>(addr);
cecLogAddrs.log_addr_type[logAddrIndex] = logAddrType;
cecLogAddrs.primary_device_type[logAddrIndex] = primDevType;
cecLogAddrs.all_device_types[logAddrIndex] = allDevTypes;
cecLogAddrs.features[logAddrIndex][0] = 0;
cecLogAddrs.features[logAddrIndex][1] = 0;
ret = ioctl(mHdmiCecPorts[0]->mCecFd, CEC_ADAP_S_LOG_ADDRS, &cecLogAddrs);
if (ret) {
LOG(ERROR) << "Add logical address failed for port " << mHdmiCecPorts[0]->mPortId
<< ", Error = " << strerror(errno);
return Result::FAILURE_BUSY;
}
return Result::SUCCESS;
}
Return<void> HdmiCec::clearLogicalAddress() {
cec_log_addrs cecLogAddrs;
memset(&cecLogAddrs, 0, sizeof(cecLogAddrs));
int ret = ioctl(mHdmiCecPorts[0]->mCecFd, CEC_ADAP_S_LOG_ADDRS, &cecLogAddrs);
if (ret) {
LOG(ERROR) << "Clear logical Address failed for port " << mHdmiCecPorts[0]->mPortId
<< ", Error = " << strerror(errno);
}
return Void();
}
Return<void> HdmiCec::getPhysicalAddress(getPhysicalAddress_cb callback) {
uint16_t addr;
int ret = ioctl(mHdmiCecPorts[0]->mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
if (ret) {
LOG(ERROR) << "Get physical address failed, Error = " << strerror(errno);
callback(Result::FAILURE_INVALID_STATE, addr);
return Void();
}
callback(Result::SUCCESS, addr);
return Void();
}
Return<SendMessageResult> HdmiCec::sendMessage(const CecMessage& message) {
if (!mCecEnabled) {
return SendMessageResult::FAIL;
}
cec_msg cecMsg;
memset(&cecMsg, 0, sizeof(cec_msg));
int initiator = static_cast<cec_logical_address_t>(message.initiator);
int destination = static_cast<cec_logical_address_t>(message.destination);
cecMsg.msg[0] = (initiator << 4) | destination;
for (size_t i = 0; i < message.body.size(); ++i) {
cecMsg.msg[i + 1] = message.body[i];
}
cecMsg.len = message.body.size() + 1;
int ret = ioctl(mHdmiCecPorts[0]->mCecFd, CEC_TRANSMIT, &cecMsg);
if (ret) {
LOG(ERROR) << "Send message failed, Error = " << strerror(errno);
return SendMessageResult::FAIL;
}
if (cecMsg.tx_status != CEC_TX_STATUS_OK) {
LOG(ERROR) << "Send message tx_status = " << cecMsg.tx_status;
}
return getSendMessageResult(cecMsg.tx_status);
}
Return<void> HdmiCec::setCallback(const sp<IHdmiCecCallback>& callback) {
if (mCallback != nullptr) {
mCallback->unlinkToDeath(this);
mCallback = nullptr;
}
if (callback != nullptr) {
mCallback = callback;
mCallback->linkToDeath(this, 0 /*cookie*/);
}
return Void();
}
Return<int32_t> HdmiCec::getCecVersion() {
return property_get_int32(PROPERTY_CEC_VERSION, CEC_OP_CEC_VERSION_1_4);
}
Return<uint32_t> HdmiCec::getVendorId() {
return property_get_int32(PROPERTY_VENDOR_ID, 0x000c03 /* HDMI LLC vendor ID */);
}
Return<void> HdmiCec::getPortInfo(getPortInfo_cb callback) {
uint16_t addr = CEC_PHYS_ADDR_INVALID;
int ret = ioctl(mHdmiCecPorts[0]->mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
if (ret) {
LOG(ERROR) << "Get port info failed for port : " << mHdmiCecPorts[0]->mPortId
<< ", Error = " << strerror(errno);
}
hidl_vec<HdmiPortInfo> portInfos {
{.type = HdmiPortType::OUTPUT,
.portId = mHdmiCecPorts[0]->mPortId,
.cecSupported = true,
.arcSupported = false,
.physicalAddress = addr}
};
callback(portInfos);
return Void();
}
Return<void> HdmiCec::setOption(OptionKey key, bool value) {
switch (key) {
case OptionKey::ENABLE_CEC:
LOG(DEBUG) << "setOption: Enable CEC: " << value;
mCecEnabled = value;
break;
case OptionKey::WAKEUP:
LOG(DEBUG) << "setOption: WAKEUP: " << value;
mWakeupEnabled = value;
break;
case OptionKey::SYSTEM_CEC_CONTROL:
LOG(DEBUG) << "setOption: SYSTEM_CEC_CONTROL: " << value;
mCecControlEnabled = value;
break;
}
return Void();
}
Return<void> HdmiCec::setLanguage(const hidl_string& language __unused) {
return Void();
}
Return<void> HdmiCec::enableAudioReturnChannel(int32_t portId __unused, bool enable __unused) {
return Void();
}
Return<bool> HdmiCec::isConnected(int32_t portId __unused) {
uint16_t addr = CEC_PHYS_ADDR_INVALID;
int ret = ioctl(mHdmiCecPorts[0]->mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
if (ret) {
LOG(ERROR) << "Is connected failed, Error = " << strerror(errno);
return false;
}
if (addr == CEC_PHYS_ADDR_INVALID) {
return false;
}
return true;
}
// Initialise the cec file descriptor
Return<Result> HdmiCec::init() {
string cecDevice = GetProperty(PROPERTY_CEC_DEVICE, "cec0");
if (cecDevice != "cec0" && cecDevice != "cec1") {
LOG(ERROR) << "Invalid CEC device " << cecDevice;
return Result::FAILURE_NOT_SUPPORTED;
}
string devicePath = "/dev/" + cecDevice;
int portId = stoi(cecDevice.substr(3));
shared_ptr<HdmiCecPort> hdmiCecPort(new HdmiCecPort(portId));
Result result = hdmiCecPort->init(devicePath.c_str());
if (result != Result::SUCCESS) {
return Result::FAILURE_NOT_SUPPORTED;
}
thread eventThread(&HdmiCec::event_thread, this, hdmiCecPort.get());
mEventThreads.push_back(std::move(eventThread));
mHdmiCecPorts.push_back(std::move(hdmiCecPort));
LOG(INFO) << "Using CEC device " << devicePath;
mCecEnabled = true;
mWakeupEnabled = true;
mCecControlEnabled = true;
return Result::SUCCESS;
}
Return<void> HdmiCec::release() {
mCecEnabled = false;
mWakeupEnabled = false;
mCecControlEnabled = false;
for (thread& eventThread : mEventThreads) {
if (eventThread.joinable()) {
eventThread.join();
}
}
setCallback(nullptr);
mHdmiCecPorts.clear();
mEventThreads.clear();
return Void();
}
void HdmiCec::event_thread(HdmiCecPort* hdmiCecPort) {
struct pollfd ufds[3] = {
{hdmiCecPort->mCecFd, POLLIN, 0},
{hdmiCecPort->mCecFd, POLLERR, 0},
{hdmiCecPort->mExitFd, POLLIN, 0},
};
while (1) {
ufds[0].revents = 0;
ufds[1].revents = 0;
ufds[2].revents = 0;
int ret = poll(ufds, /* size(ufds) = */ 3, /* timeout = */ -1);
if (ret <= 0) {
continue;
}
if (ufds[2].revents == POLLIN) { /* Exit */
break;
}
if (ufds[1].revents == POLLERR) { /* CEC Event */
cec_event ev;
ret = ioctl(hdmiCecPort->mCecFd, CEC_DQEVENT, &ev);
if (ret) {
LOG(ERROR) << "CEC_DQEVENT failed, Error = " << strerror(errno);
continue;
}
if (!mCecEnabled) {
continue;
}
if (ev.event == CEC_EVENT_STATE_CHANGE) {
if (mCallback != nullptr) {
HotplugEvent hotplugEvent{
.connected = (ev.state_change.phys_addr != CEC_PHYS_ADDR_INVALID),
.portId = hdmiCecPort->mPortId};
mCallback->onHotplugEvent(hotplugEvent);
} else {
LOG(ERROR) << "No event callback for hotplug";
}
}
}
if (ufds[0].revents == POLLIN) { /* CEC Driver */
cec_msg msg = {};
ret = ioctl(hdmiCecPort->mCecFd, CEC_RECEIVE, &msg);
if (ret) {
LOG(ERROR) << "CEC_RECEIVE failed, Error = " << strerror(errno);
continue;
}
if (msg.rx_status != CEC_RX_STATUS_OK) {
LOG(ERROR) << "msg rx_status = " << msg.rx_status;
continue;
}
if (!mCecEnabled) {
continue;
}
if (!mWakeupEnabled && isWakeupMessage(msg)) {
LOG(DEBUG) << "Filter wakeup message";
continue;
}
if (!mCecControlEnabled && !isTransferableInSleep(msg)) {
LOG(DEBUG) << "Filter message in standby mode";
continue;
}
if (mCallback != nullptr) {
size_t length = std::min(msg.len - 1, (uint32_t)MaxLength::MESSAGE_BODY);
CecMessage cecMessage{
.initiator = static_cast<CecLogicalAddress>(msg.msg[0] >> 4),
.destination = static_cast<CecLogicalAddress>(msg.msg[0] & 0xf),
};
cecMessage.body.resize(length);
for (size_t i = 0; i < length; ++i) {
cecMessage.body[i] = static_cast<uint8_t>(msg.msg[i + 1]);
}
mCallback->onCecMessage(cecMessage);
} else {
LOG(ERROR) << "no event callback for message";
}
}
}
}
int HdmiCec::getOpcode(cec_msg message) {
return static_cast<uint8_t>(message.msg[1]);
}
bool HdmiCec::isWakeupMessage(cec_msg message) {
int opcode = getOpcode(message);
switch (opcode) {
case CEC_MESSAGE_TEXT_VIEW_ON:
case CEC_MESSAGE_IMAGE_VIEW_ON:
return true;
default:
return false;
}
}
bool HdmiCec::isTransferableInSleep(cec_msg message) {
int opcode = getOpcode(message);
switch (opcode) {
case CEC_MESSAGE_ABORT:
case CEC_MESSAGE_DEVICE_VENDOR_ID:
case CEC_MESSAGE_GET_CEC_VERSION:
case CEC_MESSAGE_GET_MENU_LANGUAGE:
case CEC_MESSAGE_GIVE_DEVICE_POWER_STATUS:
case CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID:
case CEC_MESSAGE_GIVE_OSD_NAME:
case CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS:
case CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS:
case CEC_MESSAGE_REPORT_POWER_STATUS:
case CEC_MESSAGE_SET_OSD_NAME:
case CEC_MESSAGE_DECK_CONTROL:
case CEC_MESSAGE_PLAY:
case CEC_MESSAGE_IMAGE_VIEW_ON:
case CEC_MESSAGE_TEXT_VIEW_ON:
case CEC_MESSAGE_SYSTEM_AUDIO_MODE_REQUEST:
return true;
case CEC_MESSAGE_USER_CONTROL_PRESSED:
return isPowerUICommand(message);
default:
return false;
}
}
int HdmiCec::getFirstParam(cec_msg message) {
return static_cast<uint8_t>(message.msg[2]);
}
bool HdmiCec::isPowerUICommand(cec_msg message) {
int uiCommand = getFirstParam(message);
switch (uiCommand) {
case CEC_OP_UI_CMD_POWER:
case CEC_OP_UI_CMD_DEVICE_ROOT_MENU:
case CEC_OP_UI_CMD_POWER_ON_FUNCTION:
return true;
default:
return false;
}
}
Return<SendMessageResult> HdmiCec::getSendMessageResult(int tx_status) {
switch (tx_status) {
case CEC_TX_STATUS_OK:
return SendMessageResult::SUCCESS;
case CEC_TX_STATUS_ARB_LOST:
return SendMessageResult::BUSY;
case CEC_TX_STATUS_NACK:
return SendMessageResult::NACK;
default:
return SendMessageResult::FAIL;
}
}
} // namespace implementation
} // namespace V1_0
} // namespace cec
} // namespace tv
} // namespace hardware
} // namespace android

95
cec/HdmiCec.h Normal file
View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2021 The Android Open Source Project
* Copyright (C) 2025 KonstaKANG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <hardware/hdmi_cec.h>
#include <linux/cec.h>
#include <thread>
#include <vector>
#include "HdmiCecPort.h"
namespace android {
namespace hardware {
namespace tv {
namespace cec {
namespace V1_0 {
namespace implementation {
using std::shared_ptr;
using std::thread;
using std::vector;
class HdmiCec : public IHdmiCec, public hidl_death_recipient {
public:
HdmiCec();
~HdmiCec();
// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
Return<Result> addLogicalAddress(CecLogicalAddress addr) override;
Return<void> clearLogicalAddress() override;
Return<void> getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) override;
Return<SendMessageResult> sendMessage(const CecMessage& message) override;
Return<void> setCallback(const sp<IHdmiCecCallback>& callback) override;
Return<int32_t> getCecVersion() override;
Return<uint32_t> getVendorId() override;
Return<void> getPortInfo(getPortInfo_cb _hidl_cb) override;
Return<void> setOption(OptionKey key, bool value) override;
Return<void> setLanguage(const hidl_string& language) override;
Return<void> enableAudioReturnChannel(int32_t portId, bool enable) override;
Return<bool> isConnected(int32_t portId) override;
virtual void serviceDied(uint64_t, const wp<::android::hidl::base::V1_0::IBase>&) {
setCallback(nullptr);
}
Return<Result> init();
Return<void> release();
private:
void event_thread(HdmiCecPort* hdmiCecPort);
static int getOpcode(cec_msg message);
static int getFirstParam(cec_msg message);
static bool isWakeupMessage(cec_msg message);
static bool isTransferableInSleep(cec_msg message);
static bool isPowerUICommand(cec_msg message);
static Return<SendMessageResult> getSendMessageResult(int tx_status);
vector<thread> mEventThreads;
vector<shared_ptr<HdmiCecPort>> mHdmiCecPorts;
// When set to false, all the CEC commands are discarded. True by default after initialization.
bool mCecEnabled;
/*
* When set to false, HAL does not wake up the system upon receiving <Image View On> or
* <Text View On>. True by default after initialization.
*/
bool mWakeupEnabled;
/*
* Updated when system goes into or comes out of standby mode.
* When set to true, Android system is handling CEC commands.
* When set to false, microprocessor is handling CEC commands.
* True by default after initialization.
*/
bool mCecControlEnabled;
sp<IHdmiCecCallback> mCallback;
};
} // namespace implementation
} // namespace V1_0
} // namespace cec
} // namespace tv
} // namespace hardware
} // namespace android

104
cec/HdmiCecPort.cpp Normal file
View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2021 The Android Open Source Project
* Copyright (C) 2025 KonstaKANG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.tv.cec@1.0-service.rpi"
#include <android-base/logging.h>
#include <errno.h>
#include <linux/cec.h>
#include <linux/ioctl.h>
#include <sys/eventfd.h>
#include <algorithm>
#include "HdmiCecPort.h"
namespace android {
namespace hardware {
namespace tv {
namespace cec {
namespace V1_0 {
namespace implementation {
HdmiCecPort::HdmiCecPort(unsigned int portId) {
mPortId = portId;
mCecFd = -1;
mExitFd = -1;
}
HdmiCecPort::~HdmiCecPort() {
release();
}
// Initialise the cec file descriptor
Return<Result> HdmiCecPort::init(const char* path) {
mCecFd = open(path, O_RDWR);
if (mCecFd < 0) {
LOG(ERROR) << "Failed to open " << path << ", Error = " << strerror(errno);
return Result::FAILURE_NOT_SUPPORTED;
}
mExitFd = eventfd(0, EFD_NONBLOCK);
if (mExitFd < 0) {
LOG(ERROR) << "Failed to open eventfd, Error = " << strerror(errno);
release();
return Result::FAILURE_NOT_SUPPORTED;
}
// Ensure the CEC device supports required capabilities
struct cec_caps caps = {};
int ret = ioctl(mCecFd, CEC_ADAP_G_CAPS, &caps);
if (ret) {
LOG(ERROR) << "Unable to query cec adapter capabilities, Error = " << strerror(errno);
release();
return Result::FAILURE_NOT_SUPPORTED;
}
if (!(caps.capabilities & (CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH))) {
LOG(ERROR) << "Wrong cec adapter capabilities " << caps.capabilities;
release();
return Result::FAILURE_NOT_SUPPORTED;
}
uint32_t mode = CEC_MODE_INITIATOR | CEC_MODE_EXCL_FOLLOWER_PASSTHRU;
ret = ioctl(mCecFd, CEC_S_MODE, &mode);
if (ret) {
LOG(ERROR) << "Unable to set initiator mode, Error = " << strerror(errno);
release();
return Result::FAILURE_NOT_SUPPORTED;
}
return Result::SUCCESS;
}
Return<void> HdmiCecPort::release() {
if (mExitFd > 0) {
uint64_t tmp = 1;
write(mExitFd, &tmp, sizeof(tmp));
}
if (mExitFd > 0) {
close(mExitFd);
}
if (mCecFd > 0) {
close(mCecFd);
}
return Void();
}
} // namespace implementation
} // namespace V1_0
} // namespace cec
} // namespace tv
} // namespace hardware
} // namespace android

44
cec/HdmiCecPort.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2021 The Android Open Source Project
* Copyright (C) 2025 KonstaKANG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
namespace android {
namespace hardware {
namespace tv {
namespace cec {
namespace V1_0 {
namespace implementation {
class HdmiCecPort {
public:
HdmiCecPort(unsigned int portId);
~HdmiCecPort();
Return<Result> init(const char* path);
Return<void> release();
unsigned int mPortId;
int mCecFd;
int mExitFd;
};
} // namespace implementation
} // namespace V1_0
} // namespace cec
} // namespace tv
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,5 @@
service vendor.cec-hal-1-0-rpi /vendor/bin/hw/android.hardware.tv.cec@1.0-service.rpi
interface android.hardware.tv.cec@1.0::IHdmiCec default
class hal
user system
group system

View File

@@ -0,0 +1,11 @@
<manifest version="1.0" type="device">
<hal format="hidl">
<name>android.hardware.tv.cec</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>IHdmiCec</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

View File

@@ -1,616 +0,0 @@
/*
* Copyright (C) 2019 BayLibre, SAS.
* Copyright (C) 2021-2022 KonstaKANG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "hdmi_cec"
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <poll.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/cec.h>
#include <sys/eventfd.h>
#include <log/log.h>
#include <cutils/properties.h>
#include <hardware/hdmi_cec.h>
typedef struct hdmicec_context
{
hdmi_cec_device_t device; /* must be first */
int cec_fd;
unsigned int vendor_id;
unsigned int type;
unsigned int version;
struct hdmi_port_info port_info;
event_callback_t p_event_cb;
void *cb_arg;
pthread_t thread;
int exit_fd;
pthread_mutex_t options_lock;
bool cec_enabled;
bool cec_control_enabled;
} hdmicec_context_t;
static int hdmicec_add_logical_address(const struct hdmi_cec_device *dev, cec_logical_address_t addr)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)dev;
unsigned int la_type = CEC_LOG_ADDR_TYPE_UNREGISTERED;
unsigned int all_dev_types = 0;
unsigned int prim_type = 0xff;
struct cec_log_addrs laddrs;
int ret;
ALOGD("%s: addr:%x\n", __func__, addr);
if (addr >= CEC_ADDR_BROADCAST)
return -1;
ret = ioctl(ctx->cec_fd, CEC_ADAP_G_LOG_ADDRS, &laddrs);
if (ret)
return ret;
memset(&laddrs, 0, sizeof(laddrs));
laddrs.cec_version = ctx->version;
laddrs.vendor_id = ctx->vendor_id;
switch (addr) {
case CEC_LOG_ADDR_TV:
prim_type = CEC_OP_PRIM_DEVTYPE_TV;
la_type = CEC_LOG_ADDR_TYPE_TV;
all_dev_types = CEC_OP_ALL_DEVTYPE_TV;
break;
case CEC_LOG_ADDR_RECORD_1:
case CEC_LOG_ADDR_RECORD_2:
case CEC_LOG_ADDR_RECORD_3:
prim_type = CEC_OP_PRIM_DEVTYPE_RECORD;
la_type = CEC_LOG_ADDR_TYPE_RECORD;
all_dev_types = CEC_OP_ALL_DEVTYPE_RECORD;
break;
case CEC_LOG_ADDR_TUNER_1:
case CEC_LOG_ADDR_TUNER_2:
case CEC_LOG_ADDR_TUNER_3:
case CEC_LOG_ADDR_TUNER_4:
prim_type = CEC_OP_PRIM_DEVTYPE_TUNER;
la_type = CEC_LOG_ADDR_TYPE_TUNER;
all_dev_types = CEC_OP_ALL_DEVTYPE_TUNER;
break;
case CEC_LOG_ADDR_PLAYBACK_1:
case CEC_LOG_ADDR_PLAYBACK_2:
case CEC_LOG_ADDR_PLAYBACK_3:
prim_type = CEC_OP_PRIM_DEVTYPE_PLAYBACK;
la_type = CEC_LOG_ADDR_TYPE_PLAYBACK;
all_dev_types = CEC_OP_ALL_DEVTYPE_PLAYBACK;
laddrs.flags = CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU;
break;
case CEC_LOG_ADDR_AUDIOSYSTEM:
prim_type = CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM;
la_type = CEC_LOG_ADDR_TYPE_AUDIOSYSTEM;
all_dev_types = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM;
break;
case CEC_LOG_ADDR_SPECIFIC:
prim_type = CEC_OP_PRIM_DEVTYPE_PROCESSOR;
la_type = CEC_LOG_ADDR_TYPE_SPECIFIC;
all_dev_types = CEC_OP_ALL_DEVTYPE_SWITCH;
break;
case CEC_ADDR_RESERVED_1:
case CEC_ADDR_RESERVED_2:
case CEC_ADDR_UNREGISTERED:
laddrs.flags = CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK;
break;
}
laddrs.num_log_addrs = 1;
laddrs.log_addr[0] = addr;
laddrs.log_addr_type[0] = la_type;
laddrs.primary_device_type[0] = prim_type;
laddrs.all_device_types[0] = all_dev_types;
laddrs.features[0][0] = 0;
laddrs.features[0][1] = 0;
ret = ioctl(ctx->cec_fd, CEC_ADAP_S_LOG_ADDRS, &laddrs);
if (ret) {
ALOGD("%s: %m\n", __func__);
return ret;
}
ALOGD("%s: log_addr_mask=%x\n", __func__, laddrs.log_addr_mask);
return 0;
}
static void hdmicec_clear_logical_address(const struct hdmi_cec_device *dev)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)dev;
struct cec_log_addrs laddrs;
int ret;
memset(&laddrs, 0, sizeof(laddrs));
ret = ioctl(ctx->cec_fd, CEC_ADAP_S_LOG_ADDRS, &laddrs);
if (ret)
ALOGD("%s: %m\n", __func__);
}
static int hdmicec_get_physical_address(const struct hdmi_cec_device *dev, uint16_t *addr)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)dev;
int ret = ioctl(ctx->cec_fd, CEC_ADAP_G_PHYS_ADDR, addr);
if (ret)
ALOGD("%s: %m\n", __func__);
return ret;
}
static int hdmicec_send_message(const struct hdmi_cec_device *dev, const cec_message_t *msg)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)dev;
struct cec_msg cec_msg;
int ret;
pthread_mutex_lock(&ctx->options_lock);
bool cec_enabled = ctx->cec_enabled;
pthread_mutex_unlock(&ctx->options_lock);
if (!cec_enabled) {
return HDMI_RESULT_FAIL;
}
ALOGD("%s: len=%u\n", __func__, (unsigned int)msg->length);
memset(&cec_msg, 0, sizeof(cec_msg));
cec_msg.msg[0] = (msg->initiator << 4) | msg->destination;
memcpy(&cec_msg.msg[1], msg->body, msg->length);
cec_msg.len = msg->length + 1;
ret = ioctl(ctx->cec_fd, CEC_TRANSMIT, &cec_msg);
if (ret) {
ALOGD("%s: %m\n", __func__);
return HDMI_RESULT_FAIL;
}
if (cec_msg.tx_status != CEC_TX_STATUS_OK)
ALOGD("%s: tx_status=%d\n", __func__, cec_msg.tx_status);
switch (cec_msg.tx_status) {
case CEC_TX_STATUS_OK:
return HDMI_RESULT_SUCCESS;
case CEC_TX_STATUS_ARB_LOST:
return HDMI_RESULT_BUSY;
case CEC_TX_STATUS_NACK:
return HDMI_RESULT_NACK;
default:
if (cec_msg.tx_status & CEC_TX_STATUS_NACK)
return HDMI_RESULT_NACK;
return HDMI_RESULT_FAIL;
}
}
static void hdmicec_register_event_callback(const struct hdmi_cec_device *dev,
event_callback_t callback, void *arg)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)dev;
ctx->p_event_cb = callback;
ctx->cb_arg = arg;
}
static void hdmicec_get_version(const struct hdmi_cec_device *dev, int *version)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)dev;
*version = ctx->version;
}
static void hdmicec_get_vendor_id(const struct hdmi_cec_device *dev, uint32_t *vendor_id)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)dev;
*vendor_id = ctx->vendor_id;
}
static void hdmicec_get_port_info(const struct hdmi_cec_device *dev,
struct hdmi_port_info *list[], int *total)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)dev;
int ret;
ret = ioctl(ctx->cec_fd, CEC_ADAP_G_PHYS_ADDR, &ctx->port_info.physical_address);
if (ret)
ALOGD("%s: %m\n", __func__);
ALOGD("type:%s, id:%d, cec support:%d, arc support:%d, physical address:%x",
ctx->port_info.type ? "output" : "input",
ctx->port_info.port_id,
ctx->port_info.cec_supported,
ctx->port_info.arc_supported,
ctx->port_info.physical_address);
if (ctx->port_info.physical_address != CEC_PHYS_ADDR_INVALID) {
*list = &ctx->port_info;
*total = 1;
}
}
static void hdmicec_set_option(const struct hdmi_cec_device *dev, int flag, int value)
{
struct hdmicec_context* ctx = (struct hdmicec_context*)dev;
ALOGD("%s: flag=%d, value=%d", __func__, flag, value);
switch (flag) {
case HDMI_OPTION_ENABLE_CEC:
pthread_mutex_lock(&ctx->options_lock);
ctx->cec_enabled = (value == 1 ? true : false);
pthread_mutex_unlock(&ctx->options_lock);
break;
case HDMI_OPTION_WAKEUP:
// Not valid for playback devices
break;
case HDMI_OPTION_SYSTEM_CEC_CONTROL:
pthread_mutex_lock(&ctx->options_lock);
ctx->cec_control_enabled = (value == 1 ? true : false);
pthread_mutex_unlock(&ctx->options_lock);
break;
}
}
static int hdmicec_is_connected(const struct hdmi_cec_device *dev, int port_id)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)dev;
int ret;
(void)port_id;
ret = ioctl(ctx->cec_fd, CEC_ADAP_G_PHYS_ADDR,
&ctx->port_info.physical_address);
if (ret) {
ALOGD("%s: %m\n", __func__);
return ret;
}
if (ctx->port_info.physical_address == CEC_PHYS_ADDR_INVALID)
return false;
return true;
}
static int get_opcode(struct cec_msg* message) {
return (((uint8_t)message->msg[1]) & 0xff);
}
static int get_first_param(struct cec_msg* message) {
return (((uint8_t)message->msg[2]) & 0xff);
}
static bool is_power_ui_command(struct cec_msg* message) {
int ui_command = get_first_param(message);
switch (ui_command) {
case CEC_OP_UI_CMD_POWER:
case CEC_OP_UI_CMD_DEVICE_ROOT_MENU:
case CEC_OP_UI_CMD_POWER_ON_FUNCTION:
return true;
default:
return false;
}
}
static bool is_transferable_in_sleep(struct cec_msg* message) {
int opcode = get_opcode(message);
switch (opcode) {
case CEC_MESSAGE_ABORT:
case CEC_MESSAGE_DEVICE_VENDOR_ID:
case CEC_MESSAGE_GET_CEC_VERSION:
case CEC_MESSAGE_GET_MENU_LANGUAGE:
case CEC_MESSAGE_GIVE_DEVICE_POWER_STATUS:
case CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID:
case CEC_MESSAGE_GIVE_OSD_NAME:
case CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS:
case CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS:
case CEC_MESSAGE_REPORT_POWER_STATUS:
case CEC_MESSAGE_SET_OSD_NAME:
case CEC_MESSAGE_DECK_CONTROL:
case CEC_MESSAGE_PLAY:
return true;
case CEC_MESSAGE_USER_CONTROL_PRESSED:
return is_power_ui_command(message);
default:
return false;
}
}
static void *event_thread(void *arg)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)arg;
int ret;
struct pollfd ufds[3] = {
{ ctx->cec_fd, POLLIN, 0 },
{ ctx->cec_fd, POLLERR, 0 },
{ ctx->exit_fd, POLLIN, 0 },
};
ALOGI("%s start!", __func__);
while (1) {
ufds[0].revents = 0;
ufds[1].revents = 0;
ufds[2].revents = 0;
ret = poll(ufds, 3, -1);
if (ret <= 0)
continue;
if (ufds[2].revents == POLLIN) /* Exit */
break;
if (ufds[1].revents == POLLERR) { /* CEC Event */
hdmi_event_t event = { };
struct cec_event ev;
ret = ioctl(ctx->cec_fd, CEC_DQEVENT, &ev);
if (ret)
continue;
pthread_mutex_lock(&ctx->options_lock);
bool cec_enabled = ctx->cec_enabled;
pthread_mutex_unlock(&ctx->options_lock);
if (!cec_enabled) {
continue;
}
if (ev.event == CEC_EVENT_STATE_CHANGE) {
event.type = HDMI_EVENT_HOT_PLUG;
event.dev = &ctx->device;
event.hotplug.port_id = 1;
if (ev.state_change.phys_addr == CEC_PHYS_ADDR_INVALID)
event.hotplug.connected = false;
else
event.hotplug.connected = true;
if (ctx->p_event_cb != NULL) {
ctx->p_event_cb(&event, ctx->cb_arg);
} else {
ALOGE("no event callback for hotplug\n");
}
}
}
if (ufds[0].revents == POLLIN) { /* CEC Driver */
struct cec_msg msg = { };
hdmi_event_t event = { };
ret = ioctl(ctx->cec_fd, CEC_RECEIVE, &msg);
if (ret) {
ALOGE("%s: CEC_RECEIVE error (%m)\n", __func__);
continue;
}
if (msg.rx_status != CEC_RX_STATUS_OK) {
ALOGD("%s: rx_status=%d\n", __func__, msg.rx_status);
continue;
}
pthread_mutex_lock(&ctx->options_lock);
bool cec_enabled = ctx->cec_enabled;
pthread_mutex_unlock(&ctx->options_lock);
if (!cec_enabled) {
continue;
}
pthread_mutex_lock(&ctx->options_lock);
bool cec_control_enabled = ctx->cec_control_enabled;
pthread_mutex_unlock(&ctx->options_lock);
if (!cec_control_enabled && !is_transferable_in_sleep(&msg)) {
ALOGD("%s: filter message in standby mode\n", __func__);
continue;
}
if (ctx->p_event_cb != NULL) {
event.type = HDMI_EVENT_CEC_MESSAGE;
event.dev = &ctx->device;
event.cec.initiator = msg.msg[0] >> 4;
event.cec.destination = msg.msg[0] & 0xf;
event.cec.length = msg.len - 1;
memcpy(event.cec.body, &msg.msg[1], msg.len - 1);
ctx->p_event_cb(&event, ctx->cb_arg);
} else {
ALOGE("no event callback for msg\n");
}
}
}
ALOGI("%s exit!", __func__);
return NULL;
}
static void hdmicec_set_arc(const struct hdmi_cec_device *dev, int port_id, int flag)
{
(void)dev;
(void)port_id;
(void)flag;
/* Not supported */
}
static int hdmicec_close(struct hdmi_cec_device *dev)
{
struct hdmicec_context *ctx = (struct hdmicec_context *)dev;
uint64_t tmp = 1;
ALOGD("%s\n", __func__);
if (ctx->exit_fd > 0) {
write(ctx->exit_fd, &tmp, sizeof(tmp));
if (ctx->thread)
pthread_join(ctx->thread, NULL);
}
if (ctx->cec_fd > 0)
close(ctx->cec_fd);
if (ctx->exit_fd > 0)
close(ctx->exit_fd);
free(ctx);
return 0;
}
static int cec_init(struct hdmicec_context *ctx)
{
struct cec_log_addrs laddrs = {};
struct cec_caps caps = {};
uint32_t mode;
int ret;
// Ensure the CEC device supports required capabilities
ret = ioctl(ctx->cec_fd, CEC_ADAP_G_CAPS, &caps);
if (ret)
return ret;
if (!(caps.capabilities & (CEC_CAP_LOG_ADDRS |
CEC_CAP_TRANSMIT |
CEC_CAP_PASSTHROUGH))) {
ALOGE("%s: wrong cec adapter capabilities %x\n",
__func__, caps.capabilities);
return -1;
}
// This is an exclusive follower, in addition put the CEC device into passthrough mode
mode = CEC_MODE_INITIATOR | CEC_MODE_EXCL_FOLLOWER_PASSTHRU;
ret = ioctl(ctx->cec_fd, CEC_S_MODE, &mode);
if (ret)
return ret;
ctx->type = property_get_int32("ro.hdmi.device_type", CEC_DEVICE_PLAYBACK);
ctx->vendor_id = property_get_int32("ro.hdmi.vendor_id",
0x000c03 /* HDMI LLC vendor ID */);
ctx->version = property_get_bool("ro.hdmi.cec_version",
CEC_OP_CEC_VERSION_1_4);
ctx->port_info.type = ctx->type == CEC_DEVICE_TV ? HDMI_INPUT : HDMI_OUTPUT;
ctx->port_info.port_id = 1;
ctx->port_info.cec_supported = 1;
ctx->port_info.arc_supported = 0;
ALOGD("%s: type=%d\n", __func__, ctx->type);
ALOGD("%s: vendor_id=%04x\n", __func__, ctx->vendor_id);
ALOGD("%s: version=%d\n", __func__, ctx->version);
memset(&laddrs, 0, sizeof(laddrs));
ret = ioctl(ctx->cec_fd, CEC_ADAP_S_LOG_ADDRS, &laddrs);
if (ret)
return ret;
pthread_mutex_init(&ctx->options_lock, NULL);
ALOGD("%s: initialized CEC controller\n", __func__);
return ret;
}
static int open_hdmi_cec(const struct hw_module_t *module, const char *id,
struct hw_device_t **device)
{
char path[32];
char prop[PROPERTY_VALUE_MAX];
hdmicec_context_t *ctx;
int ret;
ALOGD("%s: id=%s\n", __func__, id);
ctx = malloc(sizeof(struct hdmicec_context));
if (!ctx)
return -ENOMEM;
memset(ctx, 0, sizeof(*ctx));
property_get("ro.hdmi.cec_device", prop, "cec0");
snprintf(path, sizeof(path), "/dev/%s", prop);
ctx->cec_fd = open(path, O_RDWR);
if (ctx->cec_fd < 0) {
ALOGE("faild to open %s, ret=%s\n", path, strerror(errno));
goto fail;
}
ctx->exit_fd = eventfd(0, EFD_NONBLOCK);
if (ctx->exit_fd < 0) {
ALOGE("faild to open eventfd, ret = %d\n", errno);
goto fail;
}
ctx->device.common.tag = HARDWARE_DEVICE_TAG;
ctx->device.common.version = HDMI_CEC_DEVICE_API_VERSION_1_0;
ctx->device.common.module = (struct hw_module_t *)module;
ctx->device.common.close = (int (*)(struct hw_device_t* device))hdmicec_close;
ctx->device.add_logical_address = hdmicec_add_logical_address;
ctx->device.clear_logical_address = hdmicec_clear_logical_address;
ctx->device.get_physical_address = hdmicec_get_physical_address;
ctx->device.send_message = hdmicec_send_message;
ctx->device.register_event_callback = hdmicec_register_event_callback;
ctx->device.get_version = hdmicec_get_version;
ctx->device.get_vendor_id = hdmicec_get_vendor_id;
ctx->device.get_port_info = hdmicec_get_port_info;
ctx->device.set_option = hdmicec_set_option;
ctx->device.set_audio_return_channel = hdmicec_set_arc;
ctx->device.is_connected = hdmicec_is_connected;
/* init status */
ret = cec_init(ctx);
if (ret)
goto fail;
*device = &ctx->device.common;
/* thread loop for receiving cec msg */
if (pthread_create(&ctx->thread, NULL, event_thread, ctx)) {
ALOGE("Can't create event thread: %s\n", strerror(errno));
goto fail;
}
ctx->cec_enabled = true;
ctx->cec_control_enabled = true;
return 0;
fail:
hdmicec_close((struct hdmi_cec_device *)ctx);
return -errno;
}
/* module method */
static struct hw_module_methods_t hdmi_cec_module_methods = {
.open = open_hdmi_cec,
};
/* hdmi_cec module */
struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = HDMI_CEC_HARDWARE_MODULE_ID,
.name = "Raspberry Pi HDMI CEC HAL",
.author = "The Android Open Source Project",
.methods = &hdmi_cec_module_methods,
};

49
cec/service.cpp Normal file
View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2019 The Android Open Source Project
* Copyright (C) 2025 KonstaKANG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.tv.cec@1.0-service-rpi"
#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
#include <hidl/LegacySupport.h>
#include "HdmiCec.h"
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::tv::cec::V1_0::IHdmiCec;
using android::hardware::tv::cec::V1_0::implementation::HdmiCec;
using android::OK;
using android::status_t;
int main() {
configureRpcThreadpool(1, true /* callerWillJoin */);
android::sp<IHdmiCec> service = new HdmiCec();
status_t status = service->registerAsService();
if (status != OK) {
ALOGE("Cannot register HDMI-CEC HAL service.");
return 1;
}
ALOGI("HDMI-CEC HAL ready.");
joinRpcThreadpool();
// Under normal cases, execution will not reach this line.
ALOGE("HDMI-CEC HAL failed to join thread pool.");
return 1;
}

View File

@@ -116,12 +116,14 @@ PRODUCT_COPY_FILES += \
external/libcamera/src/ipa/rpi/pisp/data/imx477_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/imx477_noir.json \
external/libcamera/src/ipa/rpi/pisp/data/imx477_scientific.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/imx477_scientific.json \
external/libcamera/src/ipa/rpi/pisp/data/imx500.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/imx500.json \
external/libcamera/src/ipa/rpi/pisp/data/imx519.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/imx519.json \
external/libcamera/src/ipa/rpi/pisp/data/imx708.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/imx708.json \
external/libcamera/src/ipa/rpi/pisp/data/imx708_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/imx708_noir.json \
external/libcamera/src/ipa/rpi/pisp/data/imx708_wide.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/imx708_wide.json \
external/libcamera/src/ipa/rpi/pisp/data/imx708_wide_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/imx708_wide_noir.json \
external/libcamera/src/ipa/rpi/pisp/data/ov5647.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/ov5647.json \
external/libcamera/src/ipa/rpi/pisp/data/ov5647_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/ov5647_noir.json
external/libcamera/src/ipa/rpi/pisp/data/ov5647_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/ov5647_noir.json \
external/libcamera/src/ipa/rpi/pisp/data/ov64a40.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/pisp/ov64a40.json
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.camera.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.xml \
@@ -136,9 +138,7 @@ PRODUCT_COPY_FILES += \
# CEC
PRODUCT_PACKAGES += \
android.hardware.tv.cec@1.0-impl \
android.hardware.tv.cec@1.0-service \
hdmi_cec.rpi
android.hardware.tv.cec@1.0-service.rpi
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.hdmi.cec.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.hdmi.cec.xml
@@ -168,8 +168,8 @@ PRODUCT_PACKAGES += \
# Graphics
PRODUCT_PACKAGES += \
android.hardware.graphics.allocator@4.0-service.minigbm_gbm_mesa \
android.hardware.graphics.mapper@4.0-impl.minigbm_gbm_mesa \
android.hardware.graphics.allocator-service.minigbm_gbm_mesa \
mapper.minigbm_gbm_mesa \
libgbm_mesa_wrapper
PRODUCT_PACKAGES += \
@@ -179,8 +179,7 @@ PRODUCT_PACKAGES += \
libEGL_mesa \
libGLESv1_CM_mesa \
libGLESv2_mesa \
libgallium_dri \
libglapi
libgallium_dri
PRODUCT_PACKAGES += \
dri_gbm \
@@ -252,6 +251,10 @@ PRODUCT_PACKAGES += \
PRODUCT_PACKAGES += \
com.android.hardware.thermal
# Touchscreen
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.touchscreen.multitouch.jazzhand.xml
# USB
PRODUCT_PACKAGES += \
android.hardware.usb-service.example \

View File

@@ -25,13 +25,57 @@ namespace aidl::android::hardware::health {
void HealthImpl::UpdateHealthInfo(HealthInfo* health_info) {
health_info->chargerAcOnline = true;
health_info->batteryLevel = 100;
health_info->batteryStatus = BatteryStatus::CHARGING;
health_info->chargerUsbOnline = true;
health_info->chargerWirelessOnline = false;
health_info->chargerDockOnline = false;
health_info->maxChargingCurrentMicroamps = 500000;
health_info->maxChargingVoltageMicrovolts = 5000000;
health_info->batteryStatus = BatteryStatus::FULL;
health_info->batteryHealth = BatteryHealth::GOOD;
health_info->batteryPresent = true;
health_info->batteryLevel = 100;
health_info->batteryVoltageMillivolts = 5000;
health_info->batteryTemperatureTenthsCelsius = 250;
health_info->batteryCurrentMicroamps = 500000;
health_info->batteryCycleCount = 25;
health_info->batteryFullChargeUah = 5000000;
health_info->batteryChargeCounterUah = 5000000;
health_info->batteryTechnology = "Li-ion";
health_info->batteryCapacityLevel = BatteryCapacityLevel::FULL;
health_info->batteryFullChargeDesignCapacityUah = 5000000;
}
ndk::ScopedAStatus HealthImpl::getChargeCounterUah(int32_t* out) {
*out = 5000000;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus HealthImpl::getCurrentNowMicroamps(int32_t* out) {
*out = 500000;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus HealthImpl::getCurrentAverageMicroamps(int32_t*) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus HealthImpl::getCapacity(int32_t* out) {
*out = 100;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus HealthImpl::getChargeStatus(BatteryStatus* out) {
*out = BatteryStatus::CHARGING;
*out = BatteryStatus::FULL;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus HealthImpl::getBatteryHealthData(BatteryHealthData* out) {
out->batteryManufacturingDateSeconds = 1231006505;
out->batteryFirstUsageSeconds = 1231469665;
out->batteryStateOfHealth = 99;
out->batterySerialNumber =
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
out->batteryPartStatus = BatteryPartStatus::ORIGINAL;
return ndk::ScopedAStatus::ok();
}

View File

@@ -28,7 +28,12 @@ public:
using Health::Health;
virtual ~HealthImpl() {}
ndk::ScopedAStatus getChargeCounterUah(int32_t* out) override;
ndk::ScopedAStatus getCurrentNowMicroamps(int32_t* out) override;
ndk::ScopedAStatus getCurrentAverageMicroamps(int32_t* out) override;
ndk::ScopedAStatus getCapacity(int32_t* out) override;
ndk::ScopedAStatus getChargeStatus(BatteryStatus* out) override;
ndk::ScopedAStatus getBatteryHealthData(BatteryHealthData* out) override;
protected:
void UpdateHealthInfo(HealthInfo* health_info) override;

View File

@@ -19,28 +19,39 @@
#include <android-base/file.h>
using ::android::base::ReadFileToString;
using ::android::base::WriteStringToFile;
namespace aidl::android::hardware::light {
static const std::string backlightFiles[] = {
"/sys/class/backlight/rpi_backlight/brightness"
};
static const uint32_t defaultMaxBrightness = 255;
const static std::vector<HwLight> availableLights = {
static const std::string backlightBrightnessPath = "/sys/class/backlight/11-0045/brightness";
static const std::string backlightMaxBrightnessPath = "/sys/class/backlight/11-0045/max_brightness";
static const std::vector<HwLight> availableLights = {
{.id = (int)LightType::BACKLIGHT, .type = LightType::BACKLIGHT, .ordinal = 0}
};
Lights::Lights() {
maxBrightness = defaultMaxBrightness;
if (!access(backlightMaxBrightnessPath.c_str(), R_OK)) {
std::string maxBrightnessValue;
if (ReadFileToString(backlightMaxBrightnessPath, &maxBrightnessValue)) {
maxBrightness = std::stoi(maxBrightnessValue);
}
}
}
ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) {
HwLight const& light = availableLights[id];
std::string const brightness = std::to_string(rgbToBrightness(state));
std::string const brightness = std::to_string(rgbToScaledBrightness(state, maxBrightness));
switch (light.type) {
case LightType::BACKLIGHT:
for (auto &file : backlightFiles) {
if (!access(file.c_str(), W_OK)) {
WriteStringToFile(brightness, file);
}
if (!access(backlightBrightnessPath.c_str(), W_OK)) {
WriteStringToFile(brightness, backlightBrightnessPath);
}
break;
default:
@@ -58,10 +69,11 @@ ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* lights) {
return ndk::ScopedAStatus::ok();
}
uint32_t Lights::rgbToBrightness(const HwLightState& state) {
uint32_t Lights::rgbToScaledBrightness(const HwLightState& state, uint32_t maxBrightness) {
uint32_t color = state.color & 0x00ffffff;
return ((77 * ((color >> 16) & 0xff)) + (150 * ((color >> 8) & 0xff)) +
uint32_t brightness = ((77 * ((color >> 16) & 0xff)) + (150 * ((color >> 8) & 0xff)) +
(29 * (color & 0xff))) >> 8;
return brightness * maxBrightness / 0xff;
}
} // aidl::android::hardware::light

View File

@@ -23,11 +23,14 @@ namespace aidl::android::hardware::light {
class Lights : public BnLights {
public:
Lights();
ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override;
ndk::ScopedAStatus getLights(std::vector<HwLight>* types) override;
private:
uint32_t rgbToBrightness(const HwLightState& state);
uint32_t maxBrightness;
uint32_t rgbToScaledBrightness(const HwLightState& state, uint32_t maxBrightness);
};
} // aidl::android::hardware::light

View File

@@ -1,6 +1,8 @@
on early-boot
chown system system /sys/class/backlight/rpi_backlight/brightness
chmod 660 /sys/class/backlight/rpi_backlight/brightness
chown system system /sys/class/backlight/11-0045/brightness
chown system system /sys/class/backlight/11-0045/max_brightness
chmod 660 /sys/class/backlight/11-0045/brightness
chmod 440 /sys/class/backlight/11-0045/max_brightness
service vendor.light-default /vendor/bin/hw/android.hardware.light-service.rpi
class hal

View File

@@ -34,13 +34,4 @@
<instance>legacy/0</instance>
</interface>
</hal>
<hal format="hidl">
<name>android.hardware.tv.cec</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>IHdmiCec</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

View File

@@ -6,14 +6,37 @@
# SPDX-License-Identifier: Apache-2.0
#
exit_with_error() {
echo $@
exit 1
}
if [ -z ${TARGET_PRODUCT} ]; then
exit_with_error "TARGET_PRODUCT environment variable is not set. Run lunch first."
fi
if [ -z ${ANDROID_PRODUCT_OUT} ]; then
exit_with_error "ANDROID_PRODUCT_OUT environment variable is not set. Run lunch first."
fi
for PARTITION in "boot" "system" "vendor"; do
if [ ! -f ${ANDROID_PRODUCT_OUT}/${PARTITION}.img ]; then
exit_with_error "Partition image not found. Run make first."
fi
done
VERSION=RaspberryVanillaAOSP15
DATE=$(date +%Y%m%d)
IMGNAME=${VERSION}-${DATE}-rpi5.img
IMGSIZE=7
OUTDIR=$(pwd | sed 's/\/device\/brcm\/rpi5$//')/out/target/product/rpi5
TARGET=$(echo ${TARGET_PRODUCT} | sed 's/^aosp_//')
IMGNAME=${VERSION}-${DATE}-${TARGET}.img
IMGSIZE=14848MiB
echo "Creating image file ${OUTDIR}/${IMGNAME}..."
sudo dd if=/dev/zero of="${OUTDIR}/${IMGNAME}" bs=1M count=$(echo "${IMGSIZE}*1024" | bc)
if [ -f ${ANDROID_PRODUCT_OUT}/${IMGNAME} ]; then
exit_with_error "${ANDROID_PRODUCT_OUT}/${IMGNAME} already exists!"
fi
echo "Creating image file ${ANDROID_PRODUCT_OUT}/${IMGNAME}..."
sudo fallocate -l ${IMGSIZE} ${ANDROID_PRODUCT_OUT}/${IMGNAME}
sync
echo "Creating partitions..."
@@ -44,28 +67,28 @@ echo c
echo a
echo 1
echo w
) | sudo fdisk "${OUTDIR}/${IMGNAME}"
) | sudo fdisk ${ANDROID_PRODUCT_OUT}/${IMGNAME}
sync
LOOPDEV=$(sudo kpartx -av "${OUTDIR}/${IMGNAME}" | awk 'NR==1{ sub(/p[0-9]$/, "", $3); print $3 }')
LOOPDEV=$(sudo kpartx -av ${ANDROID_PRODUCT_OUT}/${IMGNAME} | awk 'NR==1{ sub(/p[0-9]$/, "", $3); print $3 }')
if [ -z ${LOOPDEV} ]; then
echo "Unable to find loop device!"
exit 1
exit_with_error "Unable to find loop device!"
fi
echo "Image mounted as /dev/${LOOPDEV}"
sleep 1
echo "Copying boot..."
sudo dd if=${OUTDIR}/boot.img of=/dev/mapper/${LOOPDEV}p1 bs=1M
sudo dd if=${ANDROID_PRODUCT_OUT}/boot.img of=/dev/mapper/${LOOPDEV}p1 bs=1M
echo "Copying system..."
sudo dd if=${OUTDIR}/system.img of=/dev/mapper/${LOOPDEV}p2 bs=1M
sudo dd if=${ANDROID_PRODUCT_OUT}/system.img of=/dev/mapper/${LOOPDEV}p2 bs=1M
echo "Copying vendor..."
sudo dd if=${OUTDIR}/vendor.img of=/dev/mapper/${LOOPDEV}p3 bs=1M
sudo dd if=${ANDROID_PRODUCT_OUT}/vendor.img of=/dev/mapper/${LOOPDEV}p3 bs=1M
echo "Creating userdata..."
sudo mkfs.ext4 /dev/mapper/${LOOPDEV}p4 -I 512 -L userdata
sync
sudo kpartx -d "/dev/${LOOPDEV}"
echo "Done, created ${OUTDIR}/${IMGNAME}!"
sudo chown ${USER}:${USER} ${ANDROID_PRODUCT_OUT}/${IMGNAME}
echo "Done, created ${ANDROID_PRODUCT_OUT}/${IMGNAME}!"
exit 0

View File

@@ -6,5 +6,5 @@ runtime_resource_overlay {
name: "AndroidRpiOverlay",
resource_dirs: ["res"],
sdk_version: "current",
proprietary: true
vendor: true,
}

View File

@@ -6,5 +6,5 @@ runtime_resource_overlay {
name: "AndroidTvRpiOverlay",
resource_dirs: ["res"],
sdk_version: "current",
proprietary: true
vendor: true,
}

View File

@@ -17,17 +17,6 @@
-->
<resources>
<!-- User activity timeout: Minimum screen off timeout in milliseconds.
Sets a lower bound for the {@link Settings.System#SCREEN_OFF_TIMEOUT} setting
which determines how soon the device will go to sleep when there is no
user activity.
This value must be greater than zero, otherwise the device will immediately
fall asleep again as soon as it is awoken.
-->
<integer name="config_minimumScreenOffTimeout">86400000</integer>
<!-- Default screen brightness setting.
Must be in the range specified by minimum and maximum. -->
<integer name="config_screenBrightnessSettingDefault">128</integer>

View File

@@ -0,0 +1,10 @@
// Copyright (C) 2021-2022 KonstaKANG
//
// SPDX-License-Identifier: Apache-2.0
runtime_resource_overlay {
name: "BluetoothRpiOverlay",
resource_dirs: ["res"],
sdk_version: "current",
vendor: true,
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright (C) 2021-2022 KonstaKANG
**
** SPDX-License-Identifier: Apache-2.0
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.bluetooth.resources.rpi"
android:versionCode="1"
android:versionName="1.0">
<application android:hasCode="false" />
<overlay
android:targetPackage="com.android.bluetooth"
android:isStatic="true"
android:priority="0" />
</manifest>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2009-2012 Broadcom Corporation
Copyright (C) 2021-2022 KonstaKANG
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- If true, device requests audio focus and start avrcp updates on source start or play -->
<bool name="a2dp_sink_automatically_request_audio_focus">true</bool>
</resources>

View File

@@ -6,5 +6,5 @@ runtime_resource_overlay {
name: "CarServiceRpiOverlay",
resource_dirs: ["res"],
sdk_version: "current",
proprietary: true
vendor: true,
}

View File

@@ -6,5 +6,5 @@ runtime_resource_overlay {
name: "SettingsProviderRpiOverlay",
resource_dirs: ["res"],
sdk_version: "current",
proprietary: true
vendor: true,
}

View File

@@ -18,6 +18,9 @@
<resources>
<!-- Disable screen dimming by default -->
<bool name="def_dim_screen">false</bool>
<!-- Default screen brightness -->
<integer name="def_screen_brightness">128</integer>

View File

@@ -6,5 +6,5 @@ runtime_resource_overlay {
name: "SettingsProviderTvRpiOverlay",
resource_dirs: ["res"],
sdk_version: "current",
proprietary: true
vendor: true,
}

View File

@@ -18,6 +18,9 @@
<resources>
<!-- Disable screen dimming by default -->
<bool name="def_dim_screen">false</bool>
<!-- Default screen brightness -->
<integer name="def_screen_brightness">128</integer>

View File

@@ -6,5 +6,5 @@ runtime_resource_overlay {
name: "SettingsRpiOverlay",
resource_dirs: ["res"],
sdk_version: "current",
proprietary: true
vendor: true,
}

View File

@@ -6,5 +6,5 @@ runtime_resource_overlay {
name: "SystemUIRpiOverlay",
resource_dirs: ["res"],
sdk_version: "current",
proprietary: true
vendor: true,
}

View File

@@ -6,5 +6,5 @@ runtime_resource_overlay {
name: "WifiRpiOverlay",
resource_dirs: ["res"],
sdk_version: "current",
proprietary: true
vendor: true,
}

View File

@@ -7,3 +7,4 @@
/dev/block/mmcblk0p3 /vendor ext4 ro,barrier=1 wait,first_stage_mount
/dev/block/mmcblk0p4 /data ext4 noatime,nosuid,nodev,nomblk_io_submit,errors=panic wait,check,formattable,quota
/devices/platform/axi/*.pcie/*.usb/*/usb* auto auto defaults voldmanaged=usb:auto
/devices/platform/axi/*.usb/usb* auto auto defaults voldmanaged=usb:auto

View File

@@ -5,6 +5,7 @@
# CEC
/dev/cec0 u:object_r:cec_device:s0
/dev/cec1 u:object_r:cec_device:s0
/vendor/bin/hw/android\.hardware\.tv\.cec@1\.0-service\.rpi u:object_r:hal_tv_cec_default_exec:s0
# DRM
/vendor/bin/hw/android\.hardware\.drm-service\.clearkey u:object_r:hal_drm_clearkey_exec:s0
@@ -22,8 +23,8 @@
/dev/dri/card1 u:object_r:gpu_device:s0
/dev/dri/renderD128 u:object_r:gpu_device:s0
/vendor/bin/hw/android\.hardware\.composer\.hwc3-service\.drm u:object_r:hal_graphics_composer_default_exec:s0
/vendor/bin/hw/android\.hardware\.graphics\.allocator@4\.0-service\.minigbm_gbm_mesa u:object_r:hal_graphics_allocator_default_exec:s0
/vendor/lib(64)?/hw/android\.hardware\.graphics.mapper@4\.0-impl\.minigbm_gbm_mesa\.so u:object_r:same_process_hal_file:s0
/vendor/bin/hw/android\.hardware\.graphics\.allocator-service\.minigbm_gbm_mesa u:object_r:hal_graphics_allocator_default_exec:s0
/vendor/lib(64)?/hw/mapper\.minigbm_gbm_mesa\.so u:object_r:same_process_hal_file:s0
/vendor/lib(64)?/hw/vulkan\.broadcom\.so u:object_r:same_process_hal_file:s0
/vendor/lib(64)?/dri_gbm\.so u:object_r:same_process_hal_file:s0
/vendor/lib(64)?/libdrm\.so u:object_r:same_process_hal_file:s0
@@ -32,13 +33,14 @@
/vendor/lib{64}?/libgbm_mesa_wrapper\.so u:object_r:same_process_hal_file:s0
/vendor/lib(64)?/libglapi\.so u:object_r:same_process_hal_file:s0
/vendor/lib(64)?/libminigbm_gralloc_gbm_mesa\.so u:object_r:same_process_hal_file:s0
/vendor/lib(64)?/libminigbm_gralloc4_utils_gbm_mesa\.so u:object_r:same_process_hal_file:s0
# Health
/vendor/bin/hw/android\.hardware\.health-service\.rpi u:object_r:hal_health_default_exec:s0
# Lights
/sys/class/backlight/rpi_backlight/brightness u:object_r:sysfs_leds:s0
/sys/devices/platform/rpi_backlight/backlight/rpi_backlight/brightness u:object_r:sysfs_leds:s0
/sys/class/backlight/11-0045/brightness u:object_r:sysfs_leds:s0
/sys/class/backlight/11-0045/max_brightness u:object_r:sysfs_leds:s0
/vendor/bin/hw/android\.hardware\.light-service\.rpi u:object_r:hal_light_default_exec:s0
# Partitions

View File

@@ -1 +1,2 @@
android.hardware.drm.IDrmFactory/widevine u:object_r:hal_drm_service:s0
mapper/minigbm_gbm_mesa u:object_r:hal_graphics_mapper_service:s0

View File

@@ -6,6 +6,6 @@
cc_binary {
name: "suspend_blocker_rpi",
srcs: ["suspend_blocker_rpi.cpp"],
proprietary: true,
vendor: true,
shared_libs: ["libpower"],
}

View File

@@ -9,8 +9,10 @@ ro.hardware.audio.primary=rpi_hdmi
# Bluetooth
bluetooth.device.class_of_device?=90,2,12
bluetooth.profile.a2dp.sink.enabled?=true
bluetooth.profile.a2dp.source.enabled?=true
bluetooth.profile.asha.central.enabled?=true
bluetooth.profile.avrcp.controller.enabled?=true
bluetooth.profile.avrcp.target.enabled?=true
bluetooth.profile.bap.broadcast.assist.enabled?=true
bluetooth.profile.bap.unicast.client.enabled?=true
@@ -37,7 +39,7 @@ media.settings.xml=/vendor/etc/media_profiles_V1_0.xml
ro.hardware.camera=libcamera
# CEC
ro.hdmi.cec_device=cec0
persist.hdmi.cec_device=cec0
ro.hdmi.device_type=4
# Display