17 Commits

Author SHA1 Message Date
Konsta
e03895bd83 ramdisk: remove vold.post_fs_data_done
* This was used by FDE which was removed in Android 13.
  0803ba0985
* Fixes 3ca55b2c31.
2024-05-03 21:51:46 +03:00
Konsta
a6aeac42b1 audio: reduce id name size
* Fixes 8ea29a6c93.
2024-05-03 21:51:39 +03:00
aloshchilov
419d7029f5 car: BT AVRCP target enabled 2024-04-17 17:23:36 +03:00
adufftpc
3ae444d56d car: Disabled BT MAP causing cyclic BT reconnect
Disabled BT Message Access Profile. Allows to keep connection to the paired device
2024-04-17 17:23:26 +03:00
Konsta
3711aeb1a6 libcamera: add override service for logging 2024-04-17 17:23:17 +03:00
Konsta
f8bc3154c6 overlay: hide data saver from settings 2023-12-07 20:20:06 +02:00
Konsta
168d1e93f1 overlay: hide more battery info from settings 2023-12-07 20:20:06 +02:00
Konsta
46955e713d boot: enable arm_boost
* Increases arm_freq to 1800 on Pi4B R1.4+.
  https://www.raspberrypi.com/documentation/computers/config_txt.html#arm_boost-raspberry-pi-4-only
  https://www.raspberrypi.com/documentation/computers/config_txt.html#overclocking
2023-11-26 22:09:59 +02:00
Konsta
8ea29a6c93 audio: probe pcm card for jack & dac 2023-11-26 22:09:50 +02:00
Konsta
1042d2ea67 hdmi audio: snake_case 2023-11-26 22:09:41 +02:00
Konsta
3804a2d54e boot: disable firmware kms setup
* https://www.raspberrypi.com/documentation/computers/config_txt.html#disable_fw_kms_setup
2023-11-26 22:09:30 +02:00
Konsta
f84b2d41d7 graphics: disable gpu color transform matrix 2023-11-26 22:08:58 +02:00
Konsta
426961a804 car: reorganize makefile 2023-10-13 19:52:23 +03:00
Konsta
e2553ec70c car: add broadcastradio hidl 2023-10-13 19:43:32 +03:00
Konsta
070bcb0fd3 car: add activities_on_secondary_displays permission
* Needed to display maps in home screen.
  f5124bfe5a
2023-10-13 16:38:01 +03:00
Konsta
3a8006c220 sepolicy: update for ffmpeg service
* There's no suffix in the service's name so drop the wildcard.
2023-10-12 10:34:10 +03:00
Konsta
c06fbeb7b2 sepolicy: update drm for aidl
* There no need for the wildcards for the HIDL versions.
2023-10-12 10:34:02 +03:00
76 changed files with 891 additions and 3256 deletions

View File

@@ -10,6 +10,6 @@ PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/aosp_rpi4_tv.mk
COMMON_LUNCH_CHOICES := \
aosp_rpi4-trunk_staging-userdebug \
aosp_rpi4_car-trunk_staging-userdebug \
aosp_rpi4_tv-trunk_staging-userdebug
aosp_rpi4-userdebug \
aosp_rpi4_car-userdebug \
aosp_rpi4_tv-userdebug

View File

@@ -16,21 +16,21 @@ TARGET_ARCH := arm64
TARGET_ARCH_VARIANT := armv8-a
TARGET_CPU_ABI := arm64-v8a
TARGET_CPU_ABI2 :=
TARGET_CPU_VARIANT := generic
TARGET_CPU_VARIANT := cortex-a72
TARGET_2ND_ARCH := arm
TARGET_2ND_ARCH_VARIANT := armv7-a-neon
TARGET_2ND_CPU_ABI := armeabi-v7a
TARGET_2ND_CPU_ABI2 := armeabi
TARGET_2ND_CPU_VARIANT := generic
TARGET_2ND_CPU_VARIANT := cortex-a72
# Bluetooth
BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := $(DEVICE_PATH)/bluetooth
BOARD_HAVE_BLUETOOTH := true
# Camera
BOARD_LIBCAMERA_IPAS := rpi/vc4
BOARD_LIBCAMERA_PIPELINES := rpi/vc4
BOARD_LIBCAMERA_IPAS := raspberrypi
BOARD_LIBCAMERA_PIPELINES := raspberrypi
BOARD_LIBCAMERA_USES_MESON_BUILD := true
# Display
@@ -75,9 +75,6 @@ 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

@@ -1 +1 @@
Raspberry Vanilla AOSP 15 device configuration for Raspberry Pi 4.
Raspberry Vanilla AOSP 13 device configuration for Raspberry Pi 4.

View File

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

View File

@@ -7,24 +7,16 @@
# Inherit device configuration
$(call inherit-product, device/brcm/rpi4/device.mk)
DEVICE_CAR_PATH := device/brcm/rpi4/car
PRODUCT_AAPT_CONFIG := normal mdpi hdpi
PRODUCT_AAPT_PREF_CONFIG := hdpi
PRODUCT_CHARACTERISTICS := automotive,nosdcard
$(call inherit-product, $(SRC_TARGET_DIR)/product/full_base.mk)
$(call inherit-product, packages/services/Car/car_product/build/car.mk)
# Audio
PRODUCT_PACKAGES += \
android.hardware.automotive.audiocontrol-service.example
PRODUCT_COPY_FILES += \
$(DEVICE_CAR_PATH)/car_audio_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/car_audio_configuration.xml
# Bluetooth
PRODUCT_VENDOR_PROPERTIES += \
bluetooth.device.class_of_device=38,4,8 \
bluetooth.profile.a2dp.source.enabled=false \
bluetooth.profile.asha.central.enabled=false \
bluetooth.profile.bap.broadcast.assist.enabled=false \
bluetooth.profile.bap.unicast.client.enabled=false \
@@ -45,7 +37,7 @@ PRODUCT_VENDOR_PROPERTIES += \
# Broadcast radio
PRODUCT_PACKAGES += \
android.hardware.broadcastradio-service.default
android.hardware.broadcastradio@2.0-service
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.broadcastradio.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.broadcastradio.xml
@@ -53,19 +45,6 @@ PRODUCT_COPY_FILES += \
# Camera
ENABLE_CAMERA_SERVICE := true
# CAN
PRODUCT_PACKAGES += \
android.hardware.automotive.can-service
PRODUCT_PACKAGES += \
canhalctrl \
canhaldump \
canhalsend
# Display
PRODUCT_COPY_FILES += \
$(DEVICE_CAR_PATH)/display_settings.xml:$(TARGET_COPY_OUT_VENDOR)/etc/display_settings.xml
# EVS
ENABLE_CAREVSSERVICE_SAMPLE := true
ENABLE_EVS_SAMPLE := true
@@ -73,18 +52,11 @@ ENABLE_EVS_SERVICE := true
ENABLE_REAR_VIEW_CAMERA_SAMPLE := true
PRODUCT_COPY_FILES += \
$(DEVICE_CAR_PATH)/evs_config_override.json:${TARGET_COPY_OUT_VENDOR}/etc/automotive/evs/config_override.json
# Occupant awareness
PRODUCT_PACKAGES += \
android.hardware.automotive.occupant_awareness@1.0-service
include packages/services/Car/car_product/occupant_awareness/OccupantAwareness.mk
device/brcm/rpi4/camera/evs_config_override.json:${TARGET_COPY_OUT_SYSTEM}/etc/automotive/evs/config_override.json
# Overlays
PRODUCT_PACKAGES += \
AndroidRpiOverlay \
BluetoothRpiOverlay \
CarServiceRpiOverlay \
SettingsProviderRpiOverlay \
WifiRpiOverlay
@@ -96,7 +68,7 @@ PRODUCT_COPY_FILES += \
# Vehicle
PRODUCT_PACKAGES += \
android.hardware.automotive.vehicle@V3-default-service
android.hardware.automotive.vehicle@2.0-default-service
# Device identifier. This must come after all inclusions.
PRODUCT_DEVICE := rpi4

View File

@@ -30,7 +30,6 @@ 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",
vendor: true,
proprietary: 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",
vendor: true,
proprietary: true,
srcs: ["audio_hw_hdmi.c"],
include_dirs: [
"external/expat/lib",

View File

@@ -86,14 +86,14 @@ struct alsa_stream_out {
static int probe_pcm_out_card() {
FILE *fp;
char card_node[32];
char card_node[] = "/proc/asound/card0/id";
char card_id[16];
char card_prop[PROPERTY_VALUE_MAX];
property_get("persist.audio.device", card_prop, "");
for (int i = 0; i < 5; i++) {
snprintf(card_node, sizeof(card_node), "/proc/asound/card%d/id", i);
card_node[17] = i + '0';
if ((fp = fopen(card_node, "r")) != NULL) {
fgets(card_id, sizeof(card_id), fp);
ALOGV("%s: %s", card_node, card_id);
@@ -346,17 +346,17 @@ static int out_get_presentation_position(const struct audio_stream_out *stream,
struct alsa_stream_out *out = (struct alsa_stream_out *)stream;
int ret = -1;
if (out->pcm) {
unsigned int avail;
if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
size_t kernel_buffer_size = out->config.period_size * out->config.period_count;
int64_t signed_frames = out->written - kernel_buffer_size + avail;
if (signed_frames >= 0) {
*frames = signed_frames;
ret = 0;
if (out->pcm) {
unsigned int avail;
if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
size_t kernel_buffer_size = out->config.period_size * out->config.period_count;
int64_t signed_frames = out->written - kernel_buffer_size + avail;
if (signed_frames >= 0) {
*frames = signed_frames;
ret = 0;
}
}
}
}
return ret;
}

View File

@@ -1,33 +0,0 @@
// Copyright (C) 2020 The Android Open Source Project
// Copyright (C) 2024 KonstaKANG
//
// SPDX-License-Identifier: Apache-2.0
cc_binary {
name: "android.hardware.bluetooth-service.rpi",
relative_install_path: "hw",
init_rc: ["bluetooth-service-rpi.rc"],
vintf_fragments: ["bluetooth-service-rpi.xml"],
vendor: true,
cflags: [
"-Wall",
"-Wextra",
],
srcs: [
"BluetoothHci.cpp",
"net_bluetooth_mgmt.cpp",
"service.cpp",
],
shared_libs: [
"android.hardware.bluetooth-V1-ndk",
"libbase",
"libbinder_ndk",
"libhidlbase",
"liblog",
"libutils",
],
static_libs: [
"android.hardware.bluetooth.async",
"android.hardware.bluetooth.hci",
],
}

View File

@@ -1,227 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* Copyright (C) 2024 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.bluetooth.service.rpi"
#include "BluetoothHci.h"
#include "log/log.h"
using namespace ::android::hardware::bluetooth::hci;
using namespace ::android::hardware::bluetooth::async;
using aidl::android::hardware::bluetooth::Status;
namespace aidl::android::hardware::bluetooth::impl {
void OnDeath(void* cookie);
class BluetoothDeathRecipient {
public:
BluetoothDeathRecipient(BluetoothHci* hci) : mHci(hci) {}
void LinkToDeath(const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
mCb = cb;
clientDeathRecipient_ = AIBinder_DeathRecipient_new(OnDeath);
auto linkToDeathReturnStatus = AIBinder_linkToDeath(
mCb->asBinder().get(), clientDeathRecipient_, this /* cookie */);
LOG_ALWAYS_FATAL_IF(linkToDeathReturnStatus != STATUS_OK,
"Unable to link to death recipient");
}
void UnlinkToDeath(const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
LOG_ALWAYS_FATAL_IF(cb != mCb, "Unable to unlink mismatched pointers");
}
void serviceDied() {
if (mCb != nullptr && !AIBinder_isAlive(mCb->asBinder().get())) {
ALOGE("Bluetooth remote service has died");
} else {
ALOGE("BluetoothDeathRecipient::serviceDied called but service not dead");
return;
}
{
std::lock_guard<std::mutex> guard(mHasDiedMutex);
has_died_ = true;
}
mHci->close();
}
BluetoothHci* mHci;
std::shared_ptr<IBluetoothHciCallbacks> mCb;
AIBinder_DeathRecipient* clientDeathRecipient_;
bool getHasDied() {
std::lock_guard<std::mutex> guard(mHasDiedMutex);
return has_died_;
}
private:
std::mutex mHasDiedMutex;
bool has_died_{false};
};
void OnDeath(void* cookie) {
auto* death_recipient = static_cast<BluetoothDeathRecipient*>(cookie);
death_recipient->serviceDied();
}
BluetoothHci::BluetoothHci() {
mDeathRecipient = std::make_shared<BluetoothDeathRecipient>(this);
}
ndk::ScopedAStatus BluetoothHci::initialize(
const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
ALOGI(__func__);
if (cb == nullptr) {
ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
}
HalState old_state = HalState::READY;
{
std::lock_guard<std::mutex> guard(mStateMutex);
if (mState != HalState::READY) {
old_state = mState;
} else {
mState = HalState::INITIALIZING;
}
}
if (old_state != HalState::READY) {
ALOGE("initialize: Unexpected State %d", static_cast<int>(old_state));
close();
cb->initializationComplete(Status::ALREADY_INITIALIZED);
return ndk::ScopedAStatus::ok();
}
mCb = cb;
management_.reset(new NetBluetoothMgmt);
mFd = management_->openHci();
if (mFd < 0) {
management_.reset();
ALOGI("Unable to open Linux interface.");
mState = HalState::READY;
cb->initializationComplete(Status::UNABLE_TO_OPEN_INTERFACE);
return ndk::ScopedAStatus::ok();
}
mDeathRecipient->LinkToDeath(mCb);
mH4 = std::make_shared<H4Protocol>(
mFd,
[](const std::vector<uint8_t>& /* raw_command */) {
LOG_ALWAYS_FATAL("Unexpected command!");
},
[this](const std::vector<uint8_t>& raw_acl) {
mCb->aclDataReceived(raw_acl);
},
[this](const std::vector<uint8_t>& raw_sco) {
mCb->scoDataReceived(raw_sco);
},
[this](const std::vector<uint8_t>& raw_event) {
mCb->hciEventReceived(raw_event);
},
[this](const std::vector<uint8_t>& raw_iso) {
mCb->isoDataReceived(raw_iso);
},
[this]() {
ALOGI("HCI socket device disconnected");
mFdWatcher.StopWatchingFileDescriptors();
});
mFdWatcher.WatchFdForNonBlockingReads(mFd,
[this](int) { mH4->OnDataReady(); });
{
std::lock_guard<std::mutex> guard(mStateMutex);
mState = HalState::ONE_CLIENT;
}
ALOGI("initialization complete");
auto status = mCb->initializationComplete(Status::SUCCESS);
if (!status.isOk()) {
if (!mDeathRecipient->getHasDied()) {
ALOGE("Error sending init callback, but no death notification");
}
close();
return ndk::ScopedAStatus::fromServiceSpecificError(
STATUS_FAILED_TRANSACTION);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus BluetoothHci::close() {
ALOGI(__func__);
{
std::lock_guard<std::mutex> guard(mStateMutex);
if (mState != HalState::ONE_CLIENT) {
LOG_ALWAYS_FATAL_IF(mState == HalState::INITIALIZING,
"mState is INITIALIZING");
ALOGI("Already closed");
return ndk::ScopedAStatus::ok();
}
mState = HalState::CLOSING;
}
mFdWatcher.StopWatchingFileDescriptors();
management_->closeHci();
{
std::lock_guard<std::mutex> guard(mStateMutex);
mState = HalState::READY;
mH4 = nullptr;
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus BluetoothHci::sendHciCommand(
const std::vector<uint8_t>& packet) {
return send(PacketType::COMMAND, packet);
}
ndk::ScopedAStatus BluetoothHci::sendAclData(
const std::vector<uint8_t>& packet) {
return send(PacketType::ACL_DATA, packet);
}
ndk::ScopedAStatus BluetoothHci::sendScoData(
const std::vector<uint8_t>& packet) {
return send(PacketType::SCO_DATA, packet);
}
ndk::ScopedAStatus BluetoothHci::sendIsoData(
const std::vector<uint8_t>& packet) {
return send(PacketType::ISO_DATA, packet);
}
ndk::ScopedAStatus BluetoothHci::send(PacketType type,
const std::vector<uint8_t>& v) {
if (v.empty()) {
ALOGE("Packet is empty, no data was found to be sent");
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
std::lock_guard<std::mutex> guard(mStateMutex);
if (mH4 == nullptr) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
mH4->Send(type, v);
return ndk::ScopedAStatus::ok();
}
} // namespace aidl::android::hardware::bluetooth::impl

View File

@@ -1,75 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* Copyright (C) 2024 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.
*/
#pragma once
#include <aidl/android/hardware/bluetooth/BnBluetoothHci.h>
#include <aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.h>
#include "async_fd_watcher.h"
#include "h4_protocol.h"
#include "net_bluetooth_mgmt.h"
namespace aidl::android::hardware::bluetooth::impl {
class BluetoothDeathRecipient;
// This Bluetooth HAL implementation connects with a serial port at dev_path_.
class BluetoothHci : public BnBluetoothHci {
public:
BluetoothHci();
ndk::ScopedAStatus initialize(
const std::shared_ptr<IBluetoothHciCallbacks>& cb) override;
ndk::ScopedAStatus sendHciCommand(
const std::vector<uint8_t>& packet) override;
ndk::ScopedAStatus sendAclData(const std::vector<uint8_t>& packet) override;
ndk::ScopedAStatus sendScoData(const std::vector<uint8_t>& packet) override;
ndk::ScopedAStatus sendIsoData(const std::vector<uint8_t>& packet) override;
ndk::ScopedAStatus close() override;
private:
int mFd{-1};
std::shared_ptr<IBluetoothHciCallbacks> mCb = nullptr;
std::shared_ptr<::android::hardware::bluetooth::hci::H4Protocol> mH4;
std::shared_ptr<BluetoothDeathRecipient> mDeathRecipient;
::android::hardware::bluetooth::async::AsyncFdWatcher mFdWatcher;
[[nodiscard]] ndk::ScopedAStatus send(
::android::hardware::bluetooth::hci::PacketType type,
const std::vector<uint8_t>& packet);
std::unique_ptr<NetBluetoothMgmt> management_{};
// Don't close twice or open before close is complete
std::mutex mStateMutex;
enum class HalState {
READY,
INITIALIZING,
ONE_CLIENT,
CLOSING,
} mState{HalState::READY};
};
} // namespace aidl::android::hardware::bluetooth::impl

View File

@@ -1,6 +0,0 @@
service vendor.bluetooth-default /vendor/bin/hw/android.hardware.bluetooth-service.rpi
class hal
capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
user bluetooth
group bluetooth
task_profiles HighPerformance

View File

@@ -1,6 +0,0 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.bluetooth</name>
<fqname>IBluetoothHci/default</fqname>
</hal>
</manifest>

View File

@@ -1,278 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* Copyright (C) 2024 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.bluetooth.service.rpi"
#include "net_bluetooth_mgmt.h"
#include <fcntl.h>
#include <log/log.h>
#include <poll.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstdint>
#include <cstdlib>
#include <cstring>
// Definitions imported from <linux/net/bluetooth/bluetooth.h>
#define BTPROTO_HCI 1
// Definitions imported from <linux/net/bluetooth/hci_sock.h>
#define HCI_CHANNEL_USER 1
#define HCI_CHANNEL_CONTROL 3
#define HCI_DEV_NONE 0xffff
struct sockaddr_hci {
sa_family_t hci_family;
unsigned short hci_dev;
unsigned short hci_channel;
};
// Definitions imported from <linux/net/bluetooth/mgmt.h>
#define MGMT_OP_READ_INDEX_LIST 0x0003
#define MGMT_EV_INDEX_ADDED 0x0004
#define MGMT_EV_CMD_COMPLETE 0x0001
#define MGMT_PKT_SIZE_MAX 1024
#define MGMT_INDEX_NONE 0xFFFF
#define WRITE_NO_INTR(fn) \
do { \
} while ((fn) == -1 && errno == EINTR)
struct mgmt_pkt {
uint16_t opcode;
uint16_t index;
uint16_t len;
uint8_t data[MGMT_PKT_SIZE_MAX];
} __attribute__((packed));
struct mgmt_ev_read_index_list {
uint16_t opcode;
uint8_t status;
uint16_t num_controllers;
uint16_t index[];
} __attribute__((packed));
namespace aidl::android::hardware::bluetooth::impl {
// Wait indefinitely for the selected HCI interface to be enabled in the
// bluetooth driver.
int NetBluetoothMgmt::waitHciDev(int hci_interface) {
ALOGI("waiting for hci interface %d", hci_interface);
int ret = -1;
struct mgmt_pkt cmd;
struct pollfd pollfd;
struct sockaddr_hci hci_addr = {
.hci_family = AF_BLUETOOTH,
.hci_dev = HCI_DEV_NONE,
.hci_channel = HCI_CHANNEL_CONTROL,
};
// Open and bind a socket to the bluetooth control interface in the
// kernel driver, used to send control commands and receive control
// events.
int fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
if (fd < 0) {
ALOGE("unable to open raw bluetooth socket: %s", strerror(errno));
return -1;
}
if (bind(fd, (struct sockaddr*)&hci_addr, sizeof(hci_addr)) < 0) {
ALOGE("unable to bind bluetooth control channel: %s", strerror(errno));
goto end;
}
// Send the control command [Read Index List].
cmd = {
.opcode = MGMT_OP_READ_INDEX_LIST,
.index = MGMT_INDEX_NONE,
.len = 0,
};
if (write(fd, &cmd, 6) != 6) {
ALOGE("error writing mgmt command: %s", strerror(errno));
goto end;
}
// Poll the control socket waiting for the command response,
// and subsequent [Index Added] events. The loops continue without
// timeout until the selected hci interface is detected.
pollfd = {.fd = fd, .events = POLLIN};
for (;;) {
ret = poll(&pollfd, 1, -1);
// Poll interrupted, try again.
if (ret == -1 && (errno == EINTR || errno == EAGAIN)) {
continue;
}
// Poll failure, abandon.
if (ret == -1) {
ALOGE("poll error: %s", strerror(errno));
break;
}
// Spurious wakeup, try again.
if (ret == 0 || (pollfd.revents & POLLIN) == 0) {
continue;
}
// Read the next control event.
struct mgmt_pkt ev {};
ret = read(fd, &ev, sizeof(ev));
if (ret < 0) {
ALOGE("error reading mgmt event: %s", strerror(errno));
goto end;
}
// Received [Read Index List] command response.
if (ev.opcode == MGMT_EV_CMD_COMPLETE) {
struct mgmt_ev_read_index_list* data =
(struct mgmt_ev_read_index_list*)ev.data;
// Prefer the exact hci_interface
for (int i = 0; i < data->num_controllers; i++) {
if (data->index[i] == hci_interface) {
ALOGI("hci interface %d found", data->index[i]);
ret = data->index[i];
goto end;
}
}
// Accept a larger one if we can't find the exact one
for (int i = 0; i < data->num_controllers; i++) {
if (data->index[i] >= hci_interface) {
ALOGI("hci interface %d found", data->index[i]);
ret = data->index[i];
goto end;
}
}
}
// Received [Index Added] event.
if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
ALOGI("hci interface %d added", hci_interface);
ret = hci_interface;
goto end;
}
}
end:
::close(fd);
return ret;
}
int NetBluetoothMgmt::findRfKill() {
char rfkill_type[64];
char type[16];
int fd, size, i;
for(i = 0; rfkill_state_ == NULL; i++)
{
snprintf(rfkill_type, sizeof(rfkill_type), "/sys/class/rfkill/rfkill%d/type", i);
if ((fd = open(rfkill_type, O_RDONLY)) < 0)
{
ALOGE("open(%s) failed: %s (%d)\n", rfkill_type, strerror(errno), errno);
return -1;
}
size = read(fd, &type, sizeof(type));
::close(fd);
if ((size >= 9) && !memcmp(type, "bluetooth", 9))
{
::asprintf(&rfkill_state_, "/sys/class/rfkill/rfkill%d/state", i);
break;
}
}
return 0;
}
int NetBluetoothMgmt::rfKill(int block) {
int fd;
char on = (block)?'1':'0';
if (findRfKill() != 0) return 0;
fd = open(rfkill_state_, O_WRONLY);
if (fd < 0) {
ALOGE( "Unable to open /dev/rfkill");
return -1;
}
ssize_t len;
WRITE_NO_INTR(len = write(fd, &on, 1));
if (len < 0) {
ALOGE( "Failed to change rfkill state");
::close(fd);
return -1;
}
::close(fd);
return 0;
}
int NetBluetoothMgmt::openHci(int hci_interface) {
ALOGI("opening hci interface %d", hci_interface);
// Block Bluetooth.
rfkill_state_ = NULL;
rfKill(1);
// Wait for the HCI interface to complete initialization or to come online.
int hci = waitHciDev(hci_interface);
if (hci < 0) {
ALOGE("hci interface %d not found", hci_interface);
return -1;
}
// Open the raw HCI socket.
int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
if (fd < 0) {
ALOGE("unable to open raw bluetooth socket: %s", strerror(errno));
return -1;
}
struct sockaddr_hci hci_addr = {
.hci_family = AF_BLUETOOTH,
.hci_dev = static_cast<uint16_t>(hci),
.hci_channel = HCI_CHANNEL_USER,
};
// Bind the socket to the selected interface.
if (bind(fd, (struct sockaddr*)&hci_addr, sizeof(hci_addr)) < 0) {
ALOGE("unable to bind bluetooth user channel: %s", strerror(errno));
::close(fd);
return -1;
}
ALOGI("hci interface %d ready", hci);
bt_fd_ = fd;
return fd;
}
void NetBluetoothMgmt::closeHci() {
if (bt_fd_ != -1) {
::close(bt_fd_);
bt_fd_ = -1;
}
// Unblock Bluetooth.
rfKill(0);
free(rfkill_state_);
}
} // namespace aidl::android::hardware::bluetooth::impl

View File

@@ -1,44 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* Copyright (C) 2024 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.
*/
#pragma once
#include <unistd.h>
namespace aidl::android::hardware::bluetooth::impl {
class NetBluetoothMgmt {
public:
NetBluetoothMgmt() {}
~NetBluetoothMgmt() {
::close(bt_fd_);
}
int openHci(int hci_interface = 0);
void closeHci();
private:
int waitHciDev(int hci_interface);
int findRfKill();
int rfKill(int block);
char *rfkill_state_;
// File descriptor opened to the bluetooth user channel.
int bt_fd_{-1};
};
} // namespace aidl::android::hardware::bluetooth::impl

View File

@@ -1,50 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* Copyright (C) 2024 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 "aidl.android.hardware.bluetooth.service.rpi"
#include <aidl/android/hardware/bluetooth/IBluetoothHci.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
#include "BluetoothHci.h"
using ::aidl::android::hardware::bluetooth::impl::BluetoothHci;
using ::android::hardware::configureRpcThreadpool;
using ::android::hardware::joinRpcThreadpool;
int main(int /* argc */, char** /* argv */) {
ALOGI("Bluetooth HAL starting");
if (!ABinderProcess_setThreadPoolMaxThreadCount(0)) {
ALOGI("failed to set thread pool max thread count");
return 1;
}
std::shared_ptr<BluetoothHci> service =
ndk::SharedRefBase::make<BluetoothHci>();
std::string instance = std::string() + BluetoothHci::descriptor + "/default";
auto result =
AServiceManager_addService(service->asBinder().get(), instance.c_str());
if (result == STATUS_OK) {
ABinderProcess_joinThreadPool();
} else {
ALOGE("Could not register as a service!");
}
return 0;
}

View File

@@ -8,6 +8,9 @@ initramfs ramdisk.img followkernel
# Audio
dtparam=audio=on
# Bluetooth
dtparam=krnbt=on
# Camera
camera_auto_detect=1
start_x=1
@@ -20,11 +23,12 @@ disable_overscan=1
# Display panel
#dtoverlay=vc4-kms-dsi-7inch
#dtoverlay=vc4-kms-dsi-ili9881-7inch
#dtoverlay=rpi-backlight
# Graphics acceleration
disable_fw_kms_setup=1
dtoverlay=vc4-kms-v3d
dtoverlay=cma,cma-512
# I2C
#dtparam=i2c_arm=on

View File

@@ -8,18 +8,9 @@ cameras:
"/base/soc/i2c0mux/i2c@1/imx477@1a":
location: back
rotation: 0
"/base/soc/i2c0mux/i2c@1/imx500@1a":
location: back
rotation: 0
"/base/soc/i2c0mux/i2c@1/imx519@1a":
location: back
rotation: 0
"/base/soc/i2c0mux/i2c@1/imx708@1a":
location: back
rotation: 0
"/base/soc/i2c0mux/i2c@1/ov5647@36":
location: back
rotation: 0
"/base/soc/i2c0mux/i2c@1/ov64a40@36":
location: back
rotation: 0

View File

@@ -1,52 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
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.
-->
<!--
Defines the audio configuration in a car, including
- Audio zones
- Zone configurations (in each audio zone)
- Volume groups (in each zone configuration)
- Context to audio bus mappings (in each volume group)
in the car environment.
-->
<carAudioConfiguration version="3">
<zones>
<zone name="Primary zone" isPrimary="true" occupantZoneId="0">
<zoneConfigs>
<zoneConfig name="Config 0" isDefault="true">
<volumeGroups>
<group>
<device address="Speaker">
<context context="music"/>
<context context="navigation"/>
<context context="voice_command"/>
<context context="call_ring"/>
<context context="call"/>
<context context="alarm"/>
<context context="notification"/>
<context context="system_sound"/>
<context context="emergency"/>
<context context="safety"/>
<context context="vehicle_status"/>
<context context="announcement"/>
</device>
</group>
</volumeGroups>
</zoneConfig>
</zoneConfigs>
</zone>
</zones>
</carAudioConfiguration>

View File

@@ -1,8 +0,0 @@
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<display-settings>
<!-- Use physical port number instead of local id -->
<config identifier="1" />
<!-- Display settings for cluster -->
<display name="port:1" dontMoveToTop="true" />
</display-settings>

View File

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

View File

@@ -1,504 +0,0 @@
/*
* 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

View File

@@ -1,95 +0,0 @@
/*
* 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

View File

@@ -1,104 +0,0 @@
/*
* 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

View File

@@ -1,44 +0,0 @@
/*
* 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

@@ -1,5 +0,0 @@
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

@@ -1,11 +0,0 @@
<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>

616
cec/hdmi_cec.c Normal file
View File

@@ -0,0 +1,616 @@
/*
* 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);
*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));
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);
ctx->cec_enabled = false;
ctx->cec_control_enabled = false;
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,
};

View File

@@ -1,49 +0,0 @@
/*
* 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

@@ -31,4 +31,20 @@
<instance>default</instance>
</interface>
</hal>
<hal format="hidl" optional="false">
<name>android.system.net.netd</name>
<version>1.1</version>
<interface>
<name>INetd</name>
<instance>default</instance>
</interface>
</hal>
<hal format="hidl" optional="false">
<name>android.system.wifi.keystore</name>
<version>1.0</version>
<interface>
<name>IKeystore</name>
<instance>default</instance>
</interface>
</hal>
</compatibility-matrix>

View File

@@ -11,11 +11,8 @@ $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, frameworks/native/build/tablet-7in-xhdpi-2048-dalvik-heap.mk)
$(call inherit-product, vendor/brcm/rpi4/rpi4-vendor.mk)
# APEX
$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
# API level
PRODUCT_SHIPPING_API_LEVEL := 34
PRODUCT_SHIPPING_API_LEVEL := 33
# Audio
PRODUCT_PACKAGES += \
@@ -74,7 +71,7 @@ PRODUCT_COPY_FILES += \
# Bluetooth
PRODUCT_PACKAGES += \
android.hardware.bluetooth-service.rpi
android.hardware.bluetooth@1.1-service.btlinux
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.bluetooth.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.bluetooth.xml \
@@ -90,7 +87,7 @@ PRODUCT_COPY_FILES += \
# Camera
PRODUCT_PACKAGES += \
android.hardware.camera.provider-V1-external-service
android.hardware.camera.provider@2.5-external-service
PRODUCT_COPY_FILES += \
$(DEVICE_PATH)/camera/external_camera_config.xml:$(TARGET_COPY_OUT_VENDOR)/etc/external_camera_config.xml
@@ -101,29 +98,27 @@ PRODUCT_COPY_FILES += \
PRODUCT_PACKAGES += \
android.hardware.camera.provider@2.5-service_64 \
camera.libcamera \
ipa_rpi_vc4
ipa_rpi
PRODUCT_COPY_FILES += \
$(DEVICE_PATH)/camera/android.hardware.camera.provider@2.5-service_64.rpi.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/android.hardware.camera.provider@2.5-service_64.rpi.rc
PRODUCT_COPY_FILES += \
$(DEVICE_PATH)/camera/camera_hal.yaml:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/camera_hal.yaml \
external/libcamera/src/ipa/rpi/vc4/data/imx219.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx219.json \
external/libcamera/src/ipa/rpi/vc4/data/imx219_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx219_noir.json \
external/libcamera/src/ipa/rpi/vc4/data/imx296.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx296.json \
external/libcamera/src/ipa/rpi/vc4/data/imx296_mono.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx296_mono.json \
external/libcamera/src/ipa/rpi/vc4/data/imx477.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx477.json \
external/libcamera/src/ipa/rpi/vc4/data/imx477_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx477_noir.json \
external/libcamera/src/ipa/rpi/vc4/data/imx477_scientific.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx477_scientific.json \
external/libcamera/src/ipa/rpi/vc4/data/imx500.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx500.json \
external/libcamera/src/ipa/rpi/vc4/data/imx519.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx519.json \
external/libcamera/src/ipa/rpi/vc4/data/imx708.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx708.json \
external/libcamera/src/ipa/rpi/vc4/data/imx708_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx708_noir.json \
external/libcamera/src/ipa/rpi/vc4/data/imx708_wide.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx708_wide.json \
external/libcamera/src/ipa/rpi/vc4/data/imx708_wide_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/imx708_wide_noir.json \
external/libcamera/src/ipa/rpi/vc4/data/ov5647.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/ov5647.json \
external/libcamera/src/ipa/rpi/vc4/data/ov5647_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/ov5647_noir.json \
external/libcamera/src/ipa/rpi/vc4/data/ov64a40.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/rpi/vc4/ov64a40.json
external/libcamera/src/ipa/raspberrypi/data/imx219.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx219.json \
external/libcamera/src/ipa/raspberrypi/data/imx219_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx219_noir.json \
external/libcamera/src/ipa/raspberrypi/data/imx296.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx296.json \
external/libcamera/src/ipa/raspberrypi/data/imx296_mono.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx296_mono.json \
external/libcamera/src/ipa/raspberrypi/data/imx477.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx477.json \
external/libcamera/src/ipa/raspberrypi/data/imx477_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx477_noir.json \
external/libcamera/src/ipa/raspberrypi/data/imx477_scientific.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx477_scientific.json \
external/libcamera/src/ipa/raspberrypi/data/imx477_v1.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx477_v1.json \
external/libcamera/src/ipa/raspberrypi/data/imx708.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx708.json \
external/libcamera/src/ipa/raspberrypi/data/imx708_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx708_noir.json \
external/libcamera/src/ipa/raspberrypi/data/imx708_wide.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx708_wide.json \
external/libcamera/src/ipa/raspberrypi/data/imx708_wide_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/imx708_wide_noir.json \
external/libcamera/src/ipa/raspberrypi/data/ov5647.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/ov5647.json \
external/libcamera/src/ipa/raspberrypi/data/ov5647_noir.json:$(TARGET_COPY_OUT_VENDOR)/etc/libcamera/ipa/raspberrypi/ov5647_noir.json
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.camera.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.xml \
@@ -138,7 +133,9 @@ PRODUCT_COPY_FILES += \
# CEC
PRODUCT_PACKAGES += \
android.hardware.tv.cec@1.0-service.rpi
android.hardware.tv.cec@1.0-impl \
android.hardware.tv.cec@1.0-service \
hdmi_cec.rpi
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.hdmi.cec.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.hdmi.cec.xml
@@ -150,10 +147,6 @@ PRODUCT_SET_DEBUGFS_RESTRICTIONS := false
PRODUCT_PACKAGES += \
android.hardware.drm-service.clearkey
# Emergency info
PRODUCT_PACKAGES += \
EmergencyInfo
# Ethernet
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.ethernet.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.ethernet.xml
@@ -168,33 +161,31 @@ PRODUCT_PACKAGES += \
# Graphics
PRODUCT_PACKAGES += \
android.hardware.graphics.allocator-service.minigbm_gbm_mesa \
mapper.minigbm_gbm_mesa \
android.hardware.graphics.allocator@4.0-service.minigbm_gbm_mesa \
android.hardware.graphics.mapper@4.0-impl.minigbm_gbm_mesa \
libgbm_mesa_wrapper
PRODUCT_PACKAGES += \
android.hardware.composer.hwc3-service.drm
android.hardware.graphics.composer@2.4-service \
hwcomposer.drm
PRODUCT_PACKAGES += \
libEGL_mesa \
libGLESv1_CM_mesa \
libGLESv2_mesa \
libgallium_dri
PRODUCT_PACKAGES += \
dri_gbm \
libgbm_mesa
libgallium_dri \
libglapi
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.software.opengles.deqp.level-2024-03-01.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.opengles.deqp.level.xml
frameworks/native/data/etc/android.software.opengles.deqp.level-2022-03-01.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.opengles.deqp.level.xml
PRODUCT_PACKAGES += \
vulkan.broadcom
PRODUCT_COPY_FILES += \
$(DEVICE_PATH)/vulkan/android.hardware.vulkan.version-1_2.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml \
frameworks/native/data/etc/android.hardware.vulkan.level-0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.level.xml \
frameworks/native/data/etc/android.hardware.vulkan.version-1_3.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml \
frameworks/native/data/etc/android.software.vulkan.deqp.level-2024-03-01.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.vulkan.deqp.level.xml
frameworks/native/data/etc/android.software.vulkan.deqp.level-2022-03-01.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.vulkan.deqp.level.xml
# Health
PRODUCT_PACKAGES += \
@@ -237,7 +228,7 @@ PRODUCT_COPY_FILES += \
# Seccomp
PRODUCT_COPY_FILES += \
$(DEVICE_PATH)/seccomp_policy/android.hardware.media.c2-extended-seccomp_policy:$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/android.hardware.media.c2-extended-seccomp_policy \
$(DEVICE_PATH)/seccomp_policy/codec2.vendor.ext.policy:$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/codec2.vendor.ext.policy \
$(DEVICE_PATH)/seccomp_policy/mediacodec.policy:$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/mediacodec.policy \
$(DEVICE_PATH)/seccomp_policy/mediaswcodec.policy:$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/mediaswcodec.policy
@@ -250,16 +241,11 @@ PRODUCT_PACKAGES += \
# Thermal
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
android.hardware.thermal@2.0-service.mock
# USB
PRODUCT_PACKAGES += \
android.hardware.usb-service.example \
android.hardware.usb.gadget-service.rpi
android.hardware.usb@1.0-service
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.usb.accessory.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.usb.accessory.xml \
@@ -270,7 +256,7 @@ PRODUCT_COPY_FILES += \
PRODUCT_SOONG_NAMESPACES += external/v4l2_codec2
PRODUCT_PACKAGES += \
android.hardware.media.c2@1.2-service-v4l2 \
android.hardware.media.c2@1.0-service-v4l2 \
libc2plugin_store
PRODUCT_COPY_FILES += \
@@ -281,7 +267,7 @@ $(call inherit-product, packages/modules/Virtualization/apex/product_packages.mk
# Wifi
PRODUCT_PACKAGES += \
android.hardware.wifi-service \
android.hardware.wifi@1.0-service \
hostapd \
hostapd_cli \
libwpa_client \

View File

@@ -2,7 +2,7 @@
<hal format="hidl" optional="true">
<name>android.hardware.media.c2</name>
<transport>hwbinder</transport>
<version>1.2</version>
<version>1.0-2</version>
<interface>
<name>IComponentStore</name>
<instance>ffmpeg</instance>

View File

@@ -26,7 +26,7 @@ cc_binary {
"libhidlbase",
"liblog",
"libutils",
"android.hardware.health-V3-ndk",
"android.hardware.health-V1-ndk",
],
overrides: ["charger"],
}

View File

@@ -25,57 +25,13 @@ namespace aidl::android::hardware::health {
void HealthImpl::UpdateHealthInfo(HealthInfo* health_info) {
health_info->chargerAcOnline = true;
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();
health_info->batteryStatus = BatteryStatus::CHARGING;
health_info->batteryHealth = BatteryHealth::GOOD;
}
ndk::ScopedAStatus HealthImpl::getChargeStatus(BatteryStatus* out) {
*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;
*out = BatteryStatus::CHARGING;
return ndk::ScopedAStatus::ok();
}

View File

@@ -28,12 +28,7 @@ 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

@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.health</name>
<version>3</version>
<version>1</version>
<fqname>IHealth/default</fqname>
</hal>
</manifest>

View File

@@ -139,7 +139,7 @@ key 116 POWER
key 117 NUMPAD_EQUALS
# key 118 "KEY_KPPLUSMINUS"
key 119 BREAK
key 120 RECENT_APPS
# key 120 (undefined)
key 121 NUMPAD_COMMA
key 122 KANA
key 123 EISU
@@ -246,10 +246,6 @@ key 217 SEARCH
key 224 BRIGHTNESS_DOWN
key 225 BRIGHTNESS_UP
key 226 HEADSETHOOK
key 228 KEYBOARD_BACKLIGHT_TOGGLE
key 229 KEYBOARD_BACKLIGHT_DOWN
key 230 KEYBOARD_BACKLIGHT_UP
key 248 MUTE
key 256 BUTTON_1
key 257 BUTTON_2
@@ -303,11 +299,6 @@ key 317 BUTTON_THUMBL
key 318 BUTTON_THUMBR
key 329 STYLUS_BUTTON_TERTIARY
key 331 STYLUS_BUTTON_PRIMARY
key 332 STYLUS_BUTTON_SECONDARY
# key 352 "KEY_OK"
key 353 DPAD_CENTER
# key 354 "KEY_GOTO"
@@ -324,7 +315,7 @@ key 362 GUIDE
# key 365 "KEY_EPG"
key 366 DVR
# key 367 "KEY_MHP"
key 368 LANGUAGE_SWITCH
# key 368 "KEY_LANGUAGE"
# key 369 "KEY_TITLE"
key 370 CAPTIONS
# key 371 "KEY_ANGLE"
@@ -372,11 +363,6 @@ key 405 LAST_CHANNEL
# key 413 "KEY_DIGITS"
# key 414 "KEY_TEEN"
# key 415 "KEY_TWEN"
# key 418 "KEY_ZOOM_IN"
key 418 ZOOM_IN
# key 419 "KEY_ZOOM_OUT"
key 419 ZOOM_OUT
key 528 FOCUS
key 429 CONTACTS
@@ -424,11 +410,6 @@ key 580 APP_SWITCH
key 582 VOICE_ASSIST
# Linux KEY_ASSISTANT
key 583 ASSIST
key 585 EMOJI_PICKER
key 656 MACRO_1
key 657 MACRO_2
key 658 MACRO_3
key 659 MACRO_4
# CEC
key 352 ENTER
@@ -437,24 +418,12 @@ key 141 POWER
key 174 BACK
# Keys defined by HID usages
key usage 0x0c0065 SCREENSHOT FALLBACK_USAGE_MAPPING
key usage 0x0c0067 WINDOW FALLBACK_USAGE_MAPPING
key usage 0x0c006F BRIGHTNESS_UP FALLBACK_USAGE_MAPPING
key usage 0x0c0070 BRIGHTNESS_DOWN FALLBACK_USAGE_MAPPING
key usage 0x0c0079 KEYBOARD_BACKLIGHT_UP FALLBACK_USAGE_MAPPING
key usage 0x0c007A KEYBOARD_BACKLIGHT_DOWN FALLBACK_USAGE_MAPPING
key usage 0x0c007C KEYBOARD_BACKLIGHT_TOGGLE FALLBACK_USAGE_MAPPING
key usage 0x0c00D9 EMOJI_PICKER FALLBACK_USAGE_MAPPING
key usage 0x0c0173 MEDIA_AUDIO_TRACK FALLBACK_USAGE_MAPPING
key usage 0x0c019C PROFILE_SWITCH FALLBACK_USAGE_MAPPING
key usage 0x0c019F SETTINGS FALLBACK_USAGE_MAPPING
key usage 0x0c01A2 ALL_APPS FALLBACK_USAGE_MAPPING
key usage 0x0c0227 REFRESH FALLBACK_USAGE_MAPPING
key usage 0x0c029D LANGUAGE_SWITCH FALLBACK_USAGE_MAPPING
key usage 0x0c029F RECENT_APPS FALLBACK_USAGE_MAPPING
key usage 0x0c02A2 ALL_APPS FALLBACK_USAGE_MAPPING
key usage 0x0d0044 STYLUS_BUTTON_PRIMARY FALLBACK_USAGE_MAPPING
key usage 0x0d005a STYLUS_BUTTON_SECONDARY FALLBACK_USAGE_MAPPING
key usage 0x0c0067 WINDOW
key usage 0x0c006F BRIGHTNESS_UP
key usage 0x0c0070 BRIGHTNESS_DOWN
key usage 0x0c0173 MEDIA_AUDIO_TRACK
key usage 0x0c019C PROFILE_SWITCH
key usage 0x0c01A2 ALL_APPS
# Joystick and game controller axes.
# Axes that are not mapped will be assigned generic axis numbers by the input subsystem.
@@ -467,8 +436,8 @@ axis 0x05 RZ
axis 0x06 THROTTLE
axis 0x07 RUDDER
axis 0x08 WHEEL
axis 0x09 RTRIGGER
axis 0x0a LTRIGGER
axis 0x09 GAS
axis 0x0a BRAKE
axis 0x10 HAT_X
axis 0x11 HAT_Y

View File

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

View File

@@ -23,14 +23,11 @@ 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 maxBrightness;
uint32_t rgbToScaledBrightness(const HwLightState& state, uint32_t maxBrightness);
uint32_t rgbToBrightness(const HwLightState& state);
};
} // aidl::android::hardware::light

View File

@@ -1,8 +1,6 @@
on early-boot
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
chown system system /sys/class/backlight/rpi_backlight/brightness
chmod 660 /sys/class/backlight/rpi_backlight/brightness
service vendor.light-default /vendor/bin/hw/android.hardware.light-service.rpi
class hal

View File

@@ -1,4 +1,4 @@
<manifest version="1.0" type="device" target-level="8">
<manifest version="1.0" type="device" target-level="7">
<hal format="hidl">
<name>android.hardware.audio</name>
<transport>hwbinder</transport>
@@ -17,12 +17,13 @@
<instance>default</instance>
</interface>
</hal>
<hal format="aidl">
<name>android.hardware.camera.provider</name>
<version>1</version>
<hal format="hidl">
<name>android.hardware.bluetooth</name>
<transport>hwbinder</transport>
<version>1.1</version>
<interface>
<name>ICameraProvider</name>
<instance>external/0</instance>
<name>IBluetoothHci</name>
<instance>default</instance>
</interface>
</hal>
<hal format="hidl">
@@ -31,7 +32,39 @@
<version>2.5</version>
<interface>
<name>ICameraProvider</name>
<instance>external/0</instance>
<instance>legacy/0</instance>
</interface>
</hal>
<hal format="hidl">
<name>android.hardware.graphics.composer</name>
<transport>hwbinder</transport>
<version>2.4</version>
<interface>
<name>IComposer</name>
<instance>default</instance>
</interface>
</hal>
<hal format="hidl">
<name>android.hardware.media.omx</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>IOmx</name>
<instance>default</instance>
</interface>
<interface>
<name>IOmxStore</name>
<instance>default</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,37 +6,14 @@
# 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
VERSION=RaspberryVanillaAOSP13
DATE=$(date +%Y%m%d)
TARGET=$(echo ${TARGET_PRODUCT} | sed 's/^aosp_//')
IMGNAME=${VERSION}-${DATE}-${TARGET}.img
IMGSIZE=14848MiB
IMGNAME=${VERSION}-${DATE}-rpi4.img
IMGSIZE=7
OUTDIR=$(pwd | sed 's/\/device\/brcm\/rpi4$//')/out/target/product/rpi4
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}
echo "Creating image file ${OUTDIR}/${IMGNAME}..."
sudo dd if=/dev/zero of="${OUTDIR}/${IMGNAME}" bs=1M count=$(echo "${IMGSIZE}*1024" | bc)
sync
echo "Creating partitions..."
@@ -67,28 +44,28 @@ echo c
echo a
echo 1
echo w
) | sudo fdisk ${ANDROID_PRODUCT_OUT}/${IMGNAME}
) | sudo fdisk "${OUTDIR}/${IMGNAME}"
sync
LOOPDEV=$(sudo kpartx -av ${ANDROID_PRODUCT_OUT}/${IMGNAME} | awk 'NR==1{ sub(/p[0-9]$/, "", $3); print $3 }')
LOOPDEV=$(sudo kpartx -av "${OUTDIR}/${IMGNAME}" | awk 'NR==1{ sub(/p[0-9]$/, "", $3); print $3 }')
if [ -z ${LOOPDEV} ]; then
exit_with_error "Unable to find loop device!"
echo "Unable to find loop device!"
exit 1
fi
echo "Image mounted as /dev/${LOOPDEV}"
sleep 1
echo "Copying boot..."
sudo dd if=${ANDROID_PRODUCT_OUT}/boot.img of=/dev/mapper/${LOOPDEV}p1 bs=1M
sudo dd if=${OUTDIR}/boot.img of=/dev/mapper/${LOOPDEV}p1 bs=1M
echo "Copying system..."
sudo dd if=${ANDROID_PRODUCT_OUT}/system.img of=/dev/mapper/${LOOPDEV}p2 bs=1M
sudo dd if=${OUTDIR}/system.img of=/dev/mapper/${LOOPDEV}p2 bs=1M
echo "Copying vendor..."
sudo dd if=${ANDROID_PRODUCT_OUT}/vendor.img of=/dev/mapper/${LOOPDEV}p3 bs=1M
sudo dd if=${OUTDIR}/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}"
sudo chown ${USER}:${USER} ${ANDROID_PRODUCT_OUT}/${IMGNAME}
echo "Done, created ${OUTDIR}/${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",
vendor: true,
proprietary: true
}

View File

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

View File

@@ -17,6 +17,17 @@
-->
<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

@@ -1,10 +0,0 @@
// 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

@@ -1,19 +0,0 @@
<?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

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

View File

@@ -18,39 +18,6 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!--
Specifies configuration of displays in system telling its usage / type and assigned
occupant. DEFAULT_DISPLAY, if assigned here, should be always assigned to the DRIVER zone.
Some examples are:
<item>displayPort=0,displayType=MAIN,occupantZoneId=0,inputTypes=DPAD_KEYS|
NAVIGATE_KEYS|ROTARY_NAVIGATION</item>
<item>displayPort=1,displayType=INSTRUMENT_CLUSTER,occupantZoneId=0,
inputTypes=DPAD_KEYS</item>
<item>displayPort=2,displayType=MAIN,occupantZoneId=1,
inputTypes=TOUCH_SCREEN</item>
<item>displayPort=3,displayType=MAIN,occupantZoneId=2,
inputTypes=TOUCH_SCREEN</item>
<item>displayUniqueId=virtual:com.example:MainD,displayType=MAIN,occupantZoneId=3,
inputTypes=TOUCH_SCREEN</item>
NOTE: each item should have displayPort or displayUniqueId, if it has both, displayPort
will be used.
displayPort: Unique Port id for the physical display.
displayUniqueId: Unique Id for the display.
The unique id of the virtual display will be the form of 'virtual:<PACKAGE>:<ID>'.
displayType: Display type for the display. Use * part from
CarOccupantZoneManager.DISPLAY_TYPE_* like MAIN, INSTRUMENT_CLUSTER and
etc.
occupantZoneId: occupantZoneId specified from config_occupant_zones.
inputTypes: supported input types for the corresponding display.
-->
<string-array translatable="false" name="config_occupant_display_mapping">
<item>displayPort=0,displayType=MAIN,occupantZoneId=0,inputTypes=TOUCH_SCREEN|DPAD_KEYS|NAVIGATE_KEYS|ROTARY_NAVIGATION</item>
<item>displayPort=1,displayType=INSTRUMENT_CLUSTER,occupantZoneId=0,inputTypes=DPAD_KEYS</item>
</string-array>
<!-- Specifies notice UI that will be launched when user starts a car or do user
switching. It is recommended to use dialog with at least TYPE_APPLICATION_OVERLAY window
type to show the UI regardless of activity launches. Target package will be auto-granted

View File

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

View File

@@ -18,9 +18,6 @@
<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",
vendor: true,
proprietary: true
}

View File

@@ -18,9 +18,6 @@
<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",
vendor: true,
proprietary: true
}

View File

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

View File

@@ -20,7 +20,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
internet,bt,airplane,hotspot,dark,screenrecord,custom(com.android.permissioncontroller/.permission.service.v33.SafetyCenterQsTileService)
internet,bt,airplane,hotspot,dark,screenrecord
</string>
</resources>

View File

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

View File

@@ -1,8 +1,8 @@
on boot
mount configfs none /config
mkdir /config/usb_gadget/g1 0770
mkdir /config/usb_gadget/g1/strings/0x409 0770
write /config/usb_gadget/g1/bcdDevice 0x0440
mkdir /config/usb_gadget/g1 0770 shell shell
mkdir /config/usb_gadget/g1/strings/0x409 0770 shell shell
write /config/usb_gadget/g1/bcdDevice 0x0223
write /config/usb_gadget/g1/bcdUSB 0x0200
write /config/usb_gadget/g1/idVendor 0x18d1
write /config/usb_gadget/g1/strings/0x409/serialnumber ${ro.serialno}
@@ -15,8 +15,8 @@ on boot
mkdir /config/usb_gadget/g1/functions/audio_source.gs3
mkdir /config/usb_gadget/g1/functions/rndis.gs4
mkdir /config/usb_gadget/g1/functions/midi.gs5
mkdir /config/usb_gadget/g1/configs/b.1 0770
mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770
mkdir /config/usb_gadget/g1/configs/b.1 0770 shell shell
mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770 shell shell
write /config/usb_gadget/g1/configs/b.1/MaxPower 500
write /config/usb_gadget/g1/os_desc/b_vendor_code 0x1
write /config/usb_gadget/g1/os_desc/qw_sign "MSFT100"
@@ -25,65 +25,66 @@ on boot
mkdir /dev/usb-ffs/mtp 0770 mtp mtp
mkdir /dev/usb-ffs/ptp 0770 mtp mtp
setprop sys.usb.mtp.device_type 3
setprop sys.usb.mtp.batchcancel true
setprop vendor.usb.rndis.config rndis.gs4
symlink /config/usb_gadget/g1/configs/b.1 /config/usb_gadget/g1/os_desc/b.1
chown system system /config/usb_gadget/
chown system system /config/usb_gadget/g1
chown system system /config/usb_gadget/g1/UDC
chown system system /config/usb_gadget/g1/bDeviceClass
chown system system /config/usb_gadget/g1/bDeviceProtocol
chown system system /config/usb_gadget/g1/bDeviceSubClass
chown system system /config/usb_gadget/g1/bMaxPacketSize0
chown system system /config/usb_gadget/g1/bcdDevice
chown system system /config/usb_gadget/g1/bcdUSB
chown system system /config/usb_gadget/g1/configs
chown system system /config/usb_gadget/g1/configs/b.1
chown system system /config/usb_gadget/g1/configs/b.1/MaxPower
chown system system /config/usb_gadget/g1/configs/b.1/bmAttributes
chown system system /config/usb_gadget/g1/configs/b.1/strings
chown system system /config/usb_gadget/g1/functions
chown system system /config/usb_gadget/g1/functions/accessory.gs2
chown system system /config/usb_gadget/g1/functions/audio_source.gs3
chown system system /config/usb_gadget/g1/functions/ffs.adb
chown system system /config/usb_gadget/g1/functions/ffs.mtp
chown system system /config/usb_gadget/g1/functions/ffs.ptp
chown system system /config/usb_gadget/g1/functions/midi.gs5
chown system system /config/usb_gadget/g1/functions/midi.gs5/buflen
chown system system /config/usb_gadget/g1/functions/midi.gs5/id
chown system system /config/usb_gadget/g1/functions/midi.gs5/in_ports
chown system system /config/usb_gadget/g1/functions/midi.gs5/index
chown system system /config/usb_gadget/g1/functions/midi.gs5/out_ports
chown system system /config/usb_gadget/g1/functions/midi.gs5/qlen
chown system system /config/usb_gadget/g1/functions/rndis.gs4
chown system system /config/usb_gadget/g1/functions/rndis.gs4/class
chown system system /config/usb_gadget/g1/functions/rndis.gs4/dev_addr
chown system system /config/usb_gadget/g1/functions/rndis.gs4/host_addr
chown system system /config/usb_gadget/g1/functions/rndis.gs4/ifname
chown system system /config/usb_gadget/g1/functions/rndis.gs4/os_desc
chown system system /config/usb_gadget/g1/functions/rndis.gs4/os_desc/interface.rndis
chown system system /config/usb_gadget/g1/functions/rndis.gs4/os_desc/interface.rndis/compatible_id
chown system system /config/usb_gadget/g1/functions/rndis.gs4/os_desc/interface.rndis/sub_compatible_id
chown system system /config/usb_gadget/g1/functions/rndis.gs4/protocol
chown system system /config/usb_gadget/g1/functions/rndis.gs4/qmult
chown system system /config/usb_gadget/g1/functions/rndis.gs4/subclass
chown system system /config/usb_gadget/g1/idProduct
chown system system /config/usb_gadget/g1/idVendor
chown system system /config/usb_gadget/g1/max_speed
chown system system /config/usb_gadget/g1/os_desc
chown system system /config/usb_gadget/g1/os_desc/b.1
chown system system /config/usb_gadget/g1/os_desc/b_vendor_code
chown system system /config/usb_gadget/g1/os_desc/qw_sign
chown system system /config/usb_gadget/g1/os_desc/use
chown system system /config/usb_gadget/g1/strings
chown system system /config/usb_gadget/g1/strings/0x409
chown system system /config/usb_gadget/g1/strings/0x409/manufacturer
chown system system /config/usb_gadget/g1/strings/0x409/product
chown system system /config/usb_gadget/g1/strings/0x409/serialnumber
on property:sys.usb.controller=*
mount functionfs adb /dev/usb-ffs/adb rmode=0770,fmode=0660,uid=2000,gid=2000,no_disconnect=1
mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
mount functionfs mtp /dev/usb-ffs/mtp rmode=0770,fmode=0660,uid=1024,gid=1024,no_disconnect=1
mount functionfs ptp /dev/usb-ffs/ptp rmode=0770,fmode=0660,uid=1024,gid=1024,no_disconnect=1
setprop sys.usb.configfs 2
setprop sys.usb.configfs 1
on property:sys.usb.config=none && property:sys.usb.configfs=1
write /config/usb_gadget/g1/os_desc/use 0
on property:sys.usb.config=mtp && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x4ee1
write /config/usb_gadget/g1/os_desc/use 1
symlink /config/usb_gadget/g1/functions/ffs.mtp /config/usb_gadget/g1/configs/b.1/f1
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x4ee2
write /config/usb_gadget/g1/os_desc/use 1
symlink /config/usb_gadget/g1/functions/ffs.mtp /config/usb_gadget/g1/configs/b.1/f1
on property:sys.usb.config=rndis && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x4ee3
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x4ee4
on property:sys.usb.config=ptp && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x4ee5
write /config/usb_gadget/g1/os_desc/use 1
symlink /config/usb_gadget/g1/functions/ffs.ptp /config/usb_gadget/g1/configs/b.1/f1
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x4ee6
write /config/usb_gadget/g1/os_desc/use 1
symlink /config/usb_gadget/g1/functions/ffs.ptp /config/usb_gadget/g1/configs/b.1/f1
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x4ee7
on property:sys.usb.config=midi && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x4ee8
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=midi,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x4ee9
on property:sys.usb.config=accessory && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x2d00
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=accessory,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x2d01
on property:sys.usb.config=audio_source && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x2d02
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=audio_source,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x2d03
on property:sys.usb.config=accessory,audio_source && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x2d04
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=accessory,audio_source,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/idProduct 0x2d05

View File

@@ -16,9 +16,6 @@
# ION
/dev/ion 0664 system system
# USB
/sys/class/udc/fe980000.usb current_speed 0664 system system
# V4L2
/dev/media0 0660 media media
/dev/media1 0660 media media

View File

@@ -9,9 +9,7 @@ fstatat64: 1
fstatfs64: 1
getcwd: 1
getdents64: 1
getegid32: 1
geteuid32: 1
getgid32: 1
getuid32: 1
mmap2: 1
open: 1

View File

@@ -1,15 +1,13 @@
# Bluetooth
/sys/class/rfkill/rfkill[0-9]/state u:object_r:sysfs_bluetooth_writable:s0
/vendor/bin/hw/android\.hardware\.bluetooth-service\.rpi u:object_r:hal_bluetooth_default_exec:s0
# 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
/vendor/bin/hw/android\.hardware\.drm-service\.widevine(.*)? u:object_r:hal_drm_widevine_exec:s0
/vendor/bin/hw/android\.hardware\.drm-service\.widevine u:object_r:hal_drm_widevine_exec:s0
# FFmpeg
/vendor/bin/hw/android\.hardware\.media\.c2@1\.2-service-ffmpeg u:object_r:mediacodec_exec:s0
@@ -22,25 +20,22 @@
/dev/dri/card0 u:object_r:gpu_device:s0
/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-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/bin/hw/android\.hardware\.graphics\.allocator@4\.0-service\.minigbm_gbm_mesa u:object_r:hal_graphics_allocator_default_exec:s0
/vendor/lib(64)?/dri/libgallium_dri\.so u:object_r:same_process_hal_file: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/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
/vendor/lib(64)?/libgallium_dri\.so u:object_r:same_process_hal_file:s0
/vendor/lib(64)?/libgbm_mesa\.so u:object_r:same_process_hal_file:s0
/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/11-0045/brightness u:object_r:sysfs_leds:s0
/sys/class/backlight/11-0045/max_brightness u:object_r:sysfs_leds:s0
/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
/vendor/bin/hw/android\.hardware\.light-service\.rpi u:object_r:hal_light_default_exec:s0
# Partitions
@@ -52,8 +47,8 @@
# Suspend
/vendor/bin/suspend_blocker_rpi u:object_r:suspend_blocker_exec:s0
# USB
/vendor/bin/hw/android\.hardware\.usb\.gadget-service\.rpi u:object_r:hal_usb_gadget_default_exec:s0
# Thermal
/vendor/bin/hw/android\.hardware\.thermal@2\.0-service\.mock u:object_r:hal_thermal_default_exec:s0
# V4L2
/vendor/bin/hw/android\.hardware\.media\.c2@1\.2-service-v4l2(.*)? u:object_r:mediacodec_exec:s0
/vendor/bin/hw/android\.hardware\.media\.c2@1\.0-service-v4l2(.*)? u:object_r:mediacodec_exec:s0

View File

@@ -1,2 +1 @@
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"],
vendor: true,
proprietary: true,
shared_libs: ["libpower"],
}

View File

@@ -1,28 +0,0 @@
// Copyright (C) 2020 The Android Open Source Project
// Copyright (C) 2024 KonstaKANG
//
// SPDX-License-Identifier: Apache-2.0
cc_binary {
name: "android.hardware.usb.gadget-service.rpi",
defaults: ["hidl_defaults"],
relative_install_path: "hw",
init_rc: ["android.hardware.usb.gadget-service.rpi.rc"],
vintf_fragments: ["android.hardware.usb.gadget-service.rpi.xml"],
vendor: true,
srcs: [
"service.cpp",
"UsbGadget.cpp",
],
shared_libs: [
"android.hardware.usb.gadget-V1-ndk",
"libbinder_ndk",
"libbase",
"libcutils",
"libhardware",
"libhidlbase",
"liblog",
"libutils",
],
static_libs: ["libusbconfigfs-rpi"],
}

View File

@@ -1,309 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* Copyright (C) 2024 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.usb.gadget-service.rpi"
#include "UsbGadget.h"
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/inotify.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
namespace aidl {
namespace android {
namespace hardware {
namespace usb {
namespace gadget {
UsbGadget::UsbGadget() {
if (access(OS_DESC_PATH, R_OK) != 0) {
ALOGE("configfs setup not done yet");
abort();
}
}
void currentFunctionsAppliedCallback(bool functionsApplied, void* payload) {
UsbGadget* gadget = (UsbGadget*)payload;
gadget->mCurrentUsbFunctionsApplied = functionsApplied;
}
ScopedAStatus UsbGadget::getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback>& callback,
int64_t in_transactionId) {
if (callback == nullptr) {
return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
}
ScopedAStatus ret = callback->getCurrentUsbFunctionsCb(
mCurrentUsbFunctions,
mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED,
in_transactionId);
if (!ret.isOk())
ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.getDescription().c_str());
return ScopedAStatus::ok();
}
ScopedAStatus UsbGadget::getUsbSpeed(const shared_ptr<IUsbGadgetCallback> &callback,
int64_t in_transactionId) {
std::string current_speed;
if (ReadFileToString(SPEED_PATH, &current_speed)) {
current_speed = Trim(current_speed);
ALOGI("current USB speed is %s", current_speed.c_str());
if (current_speed == "low-speed")
mUsbSpeed = UsbSpeed::LOWSPEED;
else if (current_speed == "full-speed")
mUsbSpeed = UsbSpeed::FULLSPEED;
else if (current_speed == "high-speed")
mUsbSpeed = UsbSpeed::HIGHSPEED;
else if (current_speed == "super-speed")
mUsbSpeed = UsbSpeed::SUPERSPEED;
else if (current_speed == "super-speed-plus")
mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
else if (current_speed == "UNKNOWN")
mUsbSpeed = UsbSpeed::UNKNOWN;
else
mUsbSpeed = UsbSpeed::UNKNOWN;
} else {
ALOGE("Fail to read current speed");
mUsbSpeed = UsbSpeed::UNKNOWN;
}
if (callback) {
ScopedAStatus ret = callback->getUsbSpeedCb(mUsbSpeed, in_transactionId);
if (!ret.isOk())
ALOGE("Call to getUsbSpeedCb failed %s", ret.getDescription().c_str());
}
return ScopedAStatus::ok();
}
Status UsbGadget::tearDownGadget() {
if (resetGadget() != Status::SUCCESS) return Status::ERROR;
if (monitorFfs.isMonitorRunning()) {
monitorFfs.reset();
} else {
ALOGI("mMonitor not running");
}
return Status::SUCCESS;
}
ScopedAStatus UsbGadget::reset(const shared_ptr<IUsbGadgetCallback> &callback,
int64_t in_transactionId) {
if (!WriteStringToFile("none", PULLUP_PATH)) {
ALOGI("Gadget cannot be pulled down");
if (callback)
callback->resetCb(Status::ERROR, in_transactionId);
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-1, "Error while calling resetCb");
}
usleep(kDisconnectWaitUs);
if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
ALOGI("Gadget cannot be pulled up");
if (callback)
callback->resetCb(Status::ERROR, in_transactionId);
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-1, "Error while calling resetCb");
}
if (callback)
callback->resetCb(Status::SUCCESS, in_transactionId);
return ScopedAStatus::ok();
}
static Status validateAndSetVidPid(uint64_t functions) {
Status ret = Status::SUCCESS;
switch (functions) {
case GadgetFunction::MTP:
ret = setVidPid("0x18d1", "0x4ee1");
break;
case GadgetFunction::ADB | GadgetFunction::MTP:
ret = setVidPid("0x18d1", "0x4ee2");
break;
case GadgetFunction::RNDIS:
ret = setVidPid("0x18d1", "0x4ee3");
break;
case GadgetFunction::ADB | GadgetFunction::RNDIS:
ret = setVidPid("0x18d1", "0x4ee4");
break;
case GadgetFunction::PTP:
ret = setVidPid("0x18d1", "0x4ee5");
break;
case GadgetFunction::ADB | GadgetFunction::PTP:
ret = setVidPid("0x18d1", "0x4ee6");
break;
case GadgetFunction::ADB:
ret = setVidPid("0x18d1", "0x4ee7");
break;
case GadgetFunction::MIDI:
ret = setVidPid("0x18d1", "0x4ee8");
break;
case GadgetFunction::ADB | GadgetFunction::MIDI:
ret = setVidPid("0x18d1", "0x4ee9");
break;
case GadgetFunction::NCM:
ret = setVidPid("0x18d1", "0x4eeb");
break;
case GadgetFunction::ADB | GadgetFunction::NCM:
ret = setVidPid("0x18d1", "0x4eec");
break;
case GadgetFunction::ACCESSORY:
ret = setVidPid("0x18d1", "0x2d00");
break;
case GadgetFunction::ADB | GadgetFunction::ACCESSORY:
ret = setVidPid("0x18d1", "0x2d01");
break;
case GadgetFunction::AUDIO_SOURCE:
ret = setVidPid("0x18d1", "0x2d02");
break;
case GadgetFunction::ADB | GadgetFunction::AUDIO_SOURCE:
ret = setVidPid("0x18d1", "0x2d03");
break;
case GadgetFunction::ACCESSORY | GadgetFunction::AUDIO_SOURCE:
ret = setVidPid("0x18d1", "0x2d04");
break;
case GadgetFunction::ADB | GadgetFunction::ACCESSORY |
GadgetFunction::AUDIO_SOURCE:
ret = setVidPid("0x18d1", "0x2d05");
break;
default:
ALOGE("Combination not supported");
ret = Status::CONFIGURATION_NOT_SUPPORTED;
}
return ret;
}
Status UsbGadget::setupFunctions(long functions,
const shared_ptr<IUsbGadgetCallback> &callback, uint64_t timeout,
int64_t in_transactionId) {
bool ffsEnabled = false;
int i = 0;
if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=
Status::SUCCESS)
return Status::ERROR;
if ((functions & GadgetFunction::ADB) != 0) {
ffsEnabled = true;
if (addAdb(&monitorFfs, &i) != Status::SUCCESS) return Status::ERROR;
}
// Pull up the gadget right away when there are no ffs functions.
if (!ffsEnabled) {
if (!WriteStringToFile(kGadgetName, PULLUP_PATH))
return Status::ERROR;
mCurrentUsbFunctionsApplied = true;
if (callback)
callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
return Status::SUCCESS;
}
monitorFfs.registerFunctionsAppliedCallback(&currentFunctionsAppliedCallback, this);
// Monitors the ffs paths to pull up the gadget when descriptors are written.
// Also takes of the pulling up the gadget again if the userspace process
// dies and restarts.
monitorFfs.startMonitor();
if (kDebug) ALOGI("Mainthread in Cv");
if (callback) {
bool pullup = monitorFfs.waitForPullUp(timeout);
ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions,
pullup ? Status::SUCCESS : Status::ERROR,
in_transactionId);
if (!ret.isOk())
ALOGE("setCurrentUsbFunctionsCb error %s", ret.getMessage());
}
return Status::SUCCESS;
}
ScopedAStatus UsbGadget::setCurrentUsbFunctions(int64_t functions,
const shared_ptr<IUsbGadgetCallback> &callback,
int64_t timeoutMs,
int64_t in_transactionId) {
std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
mCurrentUsbFunctions = functions;
mCurrentUsbFunctionsApplied = false;
// Unlink the gadget and stop the monitor if running.
Status status = tearDownGadget();
if (status != Status::SUCCESS) {
goto error;
}
ALOGI("Returned from tearDown gadget");
// Leave the gadget pulled down to give time for the host to sense disconnect.
usleep(kDisconnectWaitUs);
if (functions == GadgetFunction::NONE) {
if (callback == NULL)
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-1, "callback == NULL");
ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
if (!ret.isOk())
ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-1, "Error while calling setCurrentUsbFunctionsCb");
}
status = validateAndSetVidPid(functions);
if (status != Status::SUCCESS) {
goto error;
}
status = setupFunctions(functions, callback, timeoutMs, in_transactionId);
if (status != Status::SUCCESS) {
goto error;
}
ALOGI("Usb Gadget setcurrent functions called successfully");
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-1, "Usb Gadget setcurrent functions called successfully");
error:
ALOGI("Usb Gadget setcurrent functions failed");
if (callback == NULL)
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-1, "Usb Gadget setcurrent functions failed");
ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
if (!ret.isOk())
ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-1, "Error while calling setCurrentUsbFunctionsCb");
}
} // namespace gadget
} // namespace usb
} // namespace hardware
} // namespace android
} // aidl

View File

@@ -1,98 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* Copyright (C) 2024 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.
*/
#pragma once
#include <UsbGadgetCommon.h>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include <android-base/strings.h>
#include <aidl/android/hardware/usb/gadget/BnUsbGadget.h>
#include <aidl/android/hardware/usb/gadget/BnUsbGadgetCallback.h>
#include <aidl/android/hardware/usb/gadget/GadgetFunction.h>
#include <aidl/android/hardware/usb/gadget/IUsbGadget.h>
#include <aidl/android/hardware/usb/gadget/IUsbGadgetCallback.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <utils/Log.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>
namespace aidl {
namespace android {
namespace hardware {
namespace usb {
namespace gadget {
using ::aidl::android::hardware::usb::gadget::GadgetFunction;
using ::aidl::android::hardware::usb::gadget::IUsbGadgetCallback;
using ::aidl::android::hardware::usb::gadget::IUsbGadget;
using ::aidl::android::hardware::usb::gadget::Status;
using ::aidl::android::hardware::usb::gadget::UsbSpeed;
using ::android::base::GetProperty;
using ::android::base::SetProperty;
using ::android::base::unique_fd;
using ::android::base::ReadFileToString;
using ::android::base::Trim;
using ::android::base::WriteStringToFile;
using ::ndk::ScopedAStatus;
using ::std::shared_ptr;
using ::std::string;
constexpr char kGadgetName[] = "fe980000.usb";
static MonitorFfs monitorFfs(kGadgetName);
#define UDC_PATH "/sys/class/udc/fe980000.usb/"
#define SPEED_PATH UDC_PATH "current_speed"
struct UsbGadget : public BnUsbGadget {
UsbGadget();
// Makes sure that only one request is processed at a time.
std::mutex mLockSetCurrentFunction;
long mCurrentUsbFunctions;
bool mCurrentUsbFunctionsApplied;
UsbSpeed mUsbSpeed;
ScopedAStatus setCurrentUsbFunctions(int64_t functions,
const shared_ptr<IUsbGadgetCallback> &callback,
int64_t timeoutMs, int64_t in_transactionId) override;
ScopedAStatus getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback> &callback,
int64_t in_transactionId) override;
ScopedAStatus reset(const shared_ptr<IUsbGadgetCallback> &callback,
int64_t in_transactionId) override;
ScopedAStatus getUsbSpeed(const shared_ptr<IUsbGadgetCallback> &callback,
int64_t in_transactionId) override;
private:
Status tearDownGadget();
Status setupFunctions(long functions, const shared_ptr<IUsbGadgetCallback> &callback,
uint64_t timeout, int64_t in_transactionId);
};
} // namespace gadget
} // namespace usb
} // namespace hardware
} // namespace android
} // aidl

View File

@@ -1,4 +0,0 @@
service vendor.usb_gadget-default /vendor/bin/hw/android.hardware.usb.gadget-service.rpi
class hal
user system
group system shell mtp

View File

@@ -1,10 +0,0 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.usb.gadget</name>
<version>1</version>
<interface>
<name>IUsbGadget</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

View File

@@ -1,28 +0,0 @@
// Copyright (C) 2020 The Android Open Source Project
// Copyright (C) 2024 KonstaKANG
//
// SPDX-License-Identifier: Apache-2.0
cc_library_static {
name: "libusbconfigfs-rpi",
vendor_available: true,
export_include_dirs: ["include"],
srcs: [
"UsbGadgetUtils.cpp",
"MonitorFfs.cpp",
],
cflags: [
"-Wall",
"-Werror",
],
shared_libs: [
"android.hardware.usb.gadget-V1-ndk",
"libbase",
"libcutils",
"libhidlbase",
"libutils",
],
}

View File

@@ -1,272 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* Copyright (C) 2024 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 "libusbconfigfs"
#include "include/UsbGadgetCommon.h"
namespace aidl {
namespace android {
namespace hardware {
namespace usb {
namespace gadget {
static volatile bool gadgetPullup;
MonitorFfs::MonitorFfs(const char* const gadget)
: mWatchFd(),
mEndpointList(),
mLock(),
mCv(),
mLockFd(),
mCurrentUsbFunctionsApplied(false),
mMonitor(),
mCallback(NULL),
mPayload(NULL),
mGadgetName(gadget),
mMonitorRunning(false) {
unique_fd eventFd(eventfd(0, 0));
if (eventFd == -1) {
ALOGE("mEventFd failed to create %d", errno);
abort();
}
unique_fd epollFd(epoll_create(2));
if (epollFd == -1) {
ALOGE("mEpollFd failed to create %d", errno);
abort();
}
unique_fd inotifyFd(inotify_init());
if (inotifyFd < 0) {
ALOGE("inotify init failed");
abort();
}
if (addEpollFd(epollFd, inotifyFd) == -1) abort();
if (addEpollFd(epollFd, eventFd) == -1) abort();
mEpollFd = std::move(epollFd);
mInotifyFd = std::move(inotifyFd);
mEventFd = std::move(eventFd);
gadgetPullup = false;
}
static void displayInotifyEvent(struct inotify_event* i) {
ALOGE(" wd =%2d; ", i->wd);
if (i->cookie > 0) ALOGE("cookie =%4d; ", i->cookie);
ALOGE("mask = ");
if (i->mask & IN_ACCESS) ALOGE("IN_ACCESS ");
if (i->mask & IN_ATTRIB) ALOGE("IN_ATTRIB ");
if (i->mask & IN_CLOSE_NOWRITE) ALOGE("IN_CLOSE_NOWRITE ");
if (i->mask & IN_CLOSE_WRITE) ALOGE("IN_CLOSE_WRITE ");
if (i->mask & IN_CREATE) ALOGE("IN_CREATE ");
if (i->mask & IN_DELETE) ALOGE("IN_DELETE ");
if (i->mask & IN_DELETE_SELF) ALOGE("IN_DELETE_SELF ");
if (i->mask & IN_IGNORED) ALOGE("IN_IGNORED ");
if (i->mask & IN_ISDIR) ALOGE("IN_ISDIR ");
if (i->mask & IN_MODIFY) ALOGE("IN_MODIFY ");
if (i->mask & IN_MOVE_SELF) ALOGE("IN_MOVE_SELF ");
if (i->mask & IN_MOVED_FROM) ALOGE("IN_MOVED_FROM ");
if (i->mask & IN_MOVED_TO) ALOGE("IN_MOVED_TO ");
if (i->mask & IN_OPEN) ALOGE("IN_OPEN ");
if (i->mask & IN_Q_OVERFLOW) ALOGE("IN_Q_OVERFLOW ");
if (i->mask & IN_UNMOUNT) ALOGE("IN_UNMOUNT ");
ALOGE("\n");
if (i->len > 0) ALOGE(" name = %s\n", i->name);
}
void* MonitorFfs::startMonitorFd(void* param) {
MonitorFfs* monitorFfs = (MonitorFfs*)param;
char buf[kBufferSize];
bool writeUdc = true, stopMonitor = false;
struct epoll_event events[kEpollEvents];
steady_clock::time_point disconnect;
bool descriptorWritten = true;
for (int i = 0; i < static_cast<int>(monitorFfs->mEndpointList.size()); i++) {
if (access(monitorFfs->mEndpointList.at(i).c_str(), R_OK)) {
descriptorWritten = false;
break;
}
}
// notify here if the endpoints are already present.
if (descriptorWritten) {
usleep(kPullUpDelay);
if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
lock_guard<mutex> lock(monitorFfs->mLock);
monitorFfs->mCurrentUsbFunctionsApplied = true;
monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied, monitorFfs->mPayload);
gadgetPullup = true;
writeUdc = false;
ALOGI("GADGET pulled up");
monitorFfs->mCv.notify_all();
}
}
while (!stopMonitor) {
int nrEvents = epoll_wait(monitorFfs->mEpollFd, events, kEpollEvents, -1);
if (nrEvents <= 0) {
ALOGE("epoll wait did not return descriptor number");
continue;
}
for (int i = 0; i < nrEvents; i++) {
ALOGI("event=%u on fd=%d\n", events[i].events, events[i].data.fd);
if (events[i].data.fd == monitorFfs->mInotifyFd) {
// Process all of the events in buffer returned by read().
int numRead = read(monitorFfs->mInotifyFd, buf, kBufferSize);
for (char* p = buf; p < buf + numRead;) {
struct inotify_event* event = (struct inotify_event*)p;
if (kDebug) displayInotifyEvent(event);
p += sizeof(struct inotify_event) + event->len;
bool descriptorPresent = true;
for (int j = 0; j < static_cast<int>(monitorFfs->mEndpointList.size()); j++) {
if (access(monitorFfs->mEndpointList.at(j).c_str(), R_OK)) {
if (kDebug) ALOGI("%s absent", monitorFfs->mEndpointList.at(j).c_str());
descriptorPresent = false;
break;
}
}
if (!descriptorPresent && !writeUdc) {
if (kDebug) ALOGI("endpoints not up");
writeUdc = true;
disconnect = std::chrono::steady_clock::now();
} else if (descriptorPresent && writeUdc) {
steady_clock::time_point temp = steady_clock::now();
if (std::chrono::duration_cast<microseconds>(temp - disconnect).count() <
kPullUpDelay)
usleep(kPullUpDelay);
if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
lock_guard<mutex> lock(monitorFfs->mLock);
monitorFfs->mCurrentUsbFunctionsApplied = true;
monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied,
monitorFfs->mPayload);
ALOGI("GADGET pulled up");
writeUdc = false;
gadgetPullup = true;
// notify the main thread to signal userspace.
monitorFfs->mCv.notify_all();
}
}
}
} else {
uint64_t flag;
read(monitorFfs->mEventFd, &flag, sizeof(flag));
if (flag == 100) {
stopMonitor = true;
break;
}
}
}
}
return NULL;
}
void MonitorFfs::reset() {
lock_guard<mutex> lock(mLockFd);
uint64_t flag = 100;
unsigned long ret;
if (mMonitorRunning) {
// Stop the monitor thread by writing into signal fd.
ret = TEMP_FAILURE_RETRY(write(mEventFd, &flag, sizeof(flag)));
if (ret < 0) ALOGE("Error writing eventfd errno=%d", errno);
ALOGI("mMonitor signalled to exit");
mMonitor->join();
ALOGI("mMonitor destroyed");
mMonitorRunning = false;
}
for (std::vector<int>::size_type i = 0; i != mWatchFd.size(); i++)
inotify_rm_watch(mInotifyFd, mWatchFd[i]);
mEndpointList.clear();
gadgetPullup = false;
mCallback = NULL;
mPayload = NULL;
}
bool MonitorFfs::startMonitor() {
mMonitor = unique_ptr<thread>(new thread(this->startMonitorFd, this));
mMonitorRunning = true;
return true;
}
bool MonitorFfs::isMonitorRunning() {
return mMonitorRunning;
}
bool MonitorFfs::waitForPullUp(int timeout_ms) {
std::unique_lock<std::mutex> lk(mLock);
if (gadgetPullup) return true;
if (mCv.wait_for(lk, timeout_ms * 1ms, [] { return gadgetPullup; })) {
ALOGI("monitorFfs signalled true");
return true;
} else {
ALOGI("monitorFfs signalled error");
// continue monitoring as the descriptors might be written at a later
// point.
return false;
}
}
bool MonitorFfs::addInotifyFd(string fd) {
lock_guard<mutex> lock(mLockFd);
int wfd;
wfd = inotify_add_watch(mInotifyFd, fd.c_str(), IN_ALL_EVENTS);
if (wfd == -1)
return false;
else
mWatchFd.push_back(wfd);
return true;
}
void MonitorFfs::addEndPoint(string ep) {
lock_guard<mutex> lock(mLockFd);
mEndpointList.push_back(ep);
}
void MonitorFfs::registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied,
void* payload),
void* payload) {
mCallback = callback;
mPayload = payload;
}
} // namespace gadget
} // namespace usb
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,210 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* Copyright (C) 2024 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 "libusbconfigfs"
#include "include/UsbGadgetCommon.h"
namespace aidl {
namespace android {
namespace hardware {
namespace usb {
namespace gadget {
int unlinkFunctions(const char* path) {
DIR* config = opendir(path);
struct dirent* function;
char filepath[kMaxFilePathLength];
int ret = 0;
if (config == NULL) return -1;
// d_type does not seems to be supported in /config
// so filtering by name.
while (((function = readdir(config)) != NULL)) {
if ((strstr(function->d_name, FUNCTION_NAME) == NULL)) continue;
// build the path for each file in the folder.
sprintf(filepath, "%s/%s", path, function->d_name);
ret = remove(filepath);
if (ret) {
ALOGE("Unable remove file %s errno:%d", filepath, errno);
break;
}
}
closedir(config);
return ret;
}
int addEpollFd(const unique_fd& epfd, const unique_fd& fd) {
struct epoll_event event;
int ret;
event.data.fd = fd;
event.events = EPOLLIN;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
if (ret) ALOGE("epoll_ctl error %d", errno);
return ret;
}
int linkFunction(const char* function, int index) {
char functionPath[kMaxFilePathLength];
char link[kMaxFilePathLength];
sprintf(functionPath, "%s%s", FUNCTIONS_PATH, function);
sprintf(link, "%s%d", FUNCTION_PATH, index);
if (symlink(functionPath, link)) {
ALOGE("Cannot create symlink %s -> %s errno:%d", link, functionPath, errno);
return -1;
}
return 0;
}
Status setVidPid(const char* vid, const char* pid) {
if (!WriteStringToFile(vid, VENDOR_ID_PATH)) return Status::ERROR;
if (!WriteStringToFile(pid, PRODUCT_ID_PATH)) return Status::ERROR;
return Status::SUCCESS;
}
std::string getVendorFunctions() {
if (GetProperty(kBuildType, "") == "user") return "user";
std::string bootMode = GetProperty(PERSISTENT_BOOT_MODE, "");
std::string persistVendorFunctions = GetProperty(kPersistentVendorConfig, "");
std::string vendorFunctions = GetProperty(kVendorConfig, "");
std::string ret = "";
if (vendorFunctions != "") {
ret = vendorFunctions;
} else if (bootMode == "usbradio" || bootMode == "factory" || bootMode == "ffbm-00" ||
bootMode == "ffbm-01") {
if (persistVendorFunctions != "")
ret = persistVendorFunctions;
else
ret = "diag";
// vendor.usb.config will reflect the current configured functions
SetProperty(kVendorConfig, ret);
}
return ret;
}
Status resetGadget() {
ALOGI("setCurrentUsbFunctions None");
if (!WriteStringToFile("none", PULLUP_PATH)) ALOGI("Gadget cannot be pulled down");
if (!WriteStringToFile("0", DEVICE_CLASS_PATH)) return Status::ERROR;
if (!WriteStringToFile("0", DEVICE_SUB_CLASS_PATH)) return Status::ERROR;
if (!WriteStringToFile("0", DEVICE_PROTOCOL_PATH)) return Status::ERROR;
if (!WriteStringToFile("0", DESC_USE_PATH)) return Status::ERROR;
if (unlinkFunctions(CONFIG_PATH)) return Status::ERROR;
return Status::SUCCESS;
}
Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
int* functionCount) {
if (((functions & GadgetFunction::MTP) != 0)) {
*ffsEnabled = true;
ALOGI("setCurrentUsbFunctions mtp");
if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR;
if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR;
// Add endpoints to be monitored.
monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1");
monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2");
monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3");
} else if (((functions & GadgetFunction::PTP) != 0)) {
*ffsEnabled = true;
ALOGI("setCurrentUsbFunctions ptp");
if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR;
if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR;
// Add endpoints to be monitored.
monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1");
monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2");
monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3");
}
if ((functions & GadgetFunction::MIDI) != 0) {
ALOGI("setCurrentUsbFunctions MIDI");
if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR;
}
if ((functions & GadgetFunction::ACCESSORY) != 0) {
ALOGI("setCurrentUsbFunctions Accessory");
if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR;
}
if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) {
ALOGI("setCurrentUsbFunctions Audio Source");
if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR;
}
if ((functions & GadgetFunction::RNDIS) != 0) {
ALOGI("setCurrentUsbFunctions rndis");
std::string rndisFunction = GetProperty(kVendorRndisConfig, "");
if (rndisFunction != "") {
if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;
} else {
// link gsi.rndis for older pixel projects
if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
}
}
if ((functions & GadgetFunction::NCM) != 0) {
ALOGI("setCurrentUsbFunctions ncm");
if (linkFunction("ncm.gs6", (*functionCount)++)) return Status::ERROR;
}
return Status::SUCCESS;
}
Status addAdb(MonitorFfs* monitorFfs, int* functionCount) {
ALOGI("setCurrentUsbFunctions Adb");
if (!WriteStringToFile("1", DESC_USE_PATH))
return Status::ERROR;
if (!monitorFfs->addInotifyFd("/dev/usb-ffs/adb/")) return Status::ERROR;
if (linkFunction("ffs.adb", (*functionCount)++)) return Status::ERROR;
monitorFfs->addEndPoint("/dev/usb-ffs/adb/ep1");
monitorFfs->addEndPoint("/dev/usb-ffs/adb/ep2");
ALOGI("Service started");
return Status::SUCCESS;
}
} // namespace gadget
} // namespace usb
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,182 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* Copyright (C) 2024 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.
*/
#ifndef HARDWARE_USB_USBGADGETCOMMON_H
#define HARDWARE_USB_USBGADGETCOMMON_H
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include <aidl/android/hardware/usb/gadget/IUsbGadget.h>
#include <aidl/android/hardware/usb/gadget/GadgetFunction.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/inotify.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <utils/Log.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>
namespace aidl {
namespace android {
namespace hardware {
namespace usb {
namespace gadget {
constexpr int kBufferSize = 512;
constexpr int kMaxFilePathLength = 256;
constexpr int kEpollEvents = 10;
constexpr bool kDebug = false;
constexpr int kDisconnectWaitUs = 100000;
constexpr int kPullUpDelay = 500000;
constexpr int kShutdownMonitor = 100;
constexpr char kBuildType[] = "ro.build.type";
constexpr char kPersistentVendorConfig[] = "persist.vendor.usb.usbradio.config";
constexpr char kVendorConfig[] = "vendor.usb.config";
constexpr char kVendorRndisConfig[] = "vendor.usb.rndis.config";
#define GADGET_PATH "/config/usb_gadget/g1/"
#define PULLUP_PATH GADGET_PATH "UDC"
#define PERSISTENT_BOOT_MODE "ro.bootmode"
#define VENDOR_ID_PATH GADGET_PATH "idVendor"
#define PRODUCT_ID_PATH GADGET_PATH "idProduct"
#define DEVICE_CLASS_PATH GADGET_PATH "bDeviceClass"
#define DEVICE_SUB_CLASS_PATH GADGET_PATH "bDeviceSubClass"
#define DEVICE_PROTOCOL_PATH GADGET_PATH "bDeviceProtocol"
#define DESC_USE_PATH GADGET_PATH "os_desc/use"
#define OS_DESC_PATH GADGET_PATH "os_desc/b.1"
#define CONFIG_PATH GADGET_PATH "configs/b.1/"
#define FUNCTIONS_PATH GADGET_PATH "functions/"
#define FUNCTION_NAME "function"
#define FUNCTION_PATH CONFIG_PATH FUNCTION_NAME
#define RNDIS_PATH FUNCTIONS_PATH "gsi.rndis"
using ::android::base::GetProperty;
using ::android::base::SetProperty;
using ::android::base::unique_fd;
using ::android::base::WriteStringToFile;
using ::aidl::android::hardware::usb::gadget::GadgetFunction;
using ::aidl::android::hardware::usb::gadget::Status;
using ::std::lock_guard;
using ::std::move;
using ::std::mutex;
using ::std::string;
using ::std::thread;
using ::std::unique_ptr;
using ::std::vector;
using ::std::chrono::microseconds;
using ::std::chrono::steady_clock;
using ::std::literals::chrono_literals::operator""ms;
// MonitorFfs automously manages gadget pullup by monitoring
// the ep file status. Restarts the usb gadget when the ep
// owner restarts.
class MonitorFfs {
private:
// Monitors the endpoints Inotify events.
unique_fd mInotifyFd;
// Control pipe for shutting down the mMonitor thread.
// mMonitor exits when SHUTDOWN_MONITOR is written into
// mEventFd/
unique_fd mEventFd;
// Pools on mInotifyFd and mEventFd.
unique_fd mEpollFd;
vector<int> mWatchFd;
// Maintains the list of Endpoints.
vector<string> mEndpointList;
// protects the CV.
std::mutex mLock;
std::condition_variable mCv;
// protects mInotifyFd, mEpollFd.
std::mutex mLockFd;
// Flag to maintain the current status of gadget pullup.
bool mCurrentUsbFunctionsApplied;
// Thread object that executes the ep monitoring logic.
unique_ptr<thread> mMonitor;
// Callback to be invoked when gadget is pulled up.
void (*mCallback)(bool functionsApplied, void* payload);
void* mPayload;
// Name of the USB gadget. Used for pullup.
const char* const mGadgetName;
// Monitor State
bool mMonitorRunning;
public:
MonitorFfs(const char* const gadget);
// Inits all the UniqueFds.
void reset();
// Starts monitoring endpoints and pullup the gadget when
// the descriptors are written.
bool startMonitor();
// Waits for timeout_ms for gadget pull up to happen.
// Returns immediately if the gadget is already pulled up.
bool waitForPullUp(int timeout_ms);
// Adds the given fd to the watch list.
bool addInotifyFd(string fd);
// Adds the given endpoint to the watch list.
void addEndPoint(string ep);
// Registers the async callback from the caller to notify the caller
// when the gadget pull up happens.
void registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied, void*(payload)),
void* payload);
bool isMonitorRunning();
// Ep monitoring and the gadget pull up logic.
static void* startMonitorFd(void* param);
};
//**************** Helper functions ************************//
// Adds the given fd to the epollfd(epfd).
int addEpollFd(const unique_fd& epfd, const unique_fd& fd);
// Removes all the usb functions link in the specified path.
int unlinkFunctions(const char* path);
// Craetes a configfs link for the function.
int linkFunction(const char* function, int index);
// Sets the USB VID and PID.
Status setVidPid(const char* vid, const char* pid);
// Extracts vendor functions from the vendor init properties.
std::string getVendorFunctions();
// Adds Adb to the usb configuration.
Status addAdb(MonitorFfs* monitorFfs, int* functionCount);
// Adds all applicable generic android usb functions other than ADB.
Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
int* functionCount);
// Pulls down USB gadget.
Status resetGadget();
} // namespace gadget
} // namespace usb
} // namespace hardware
} // namespace android
} // namespace aidl
#endif

View File

@@ -1,33 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* Copyright (C) 2024 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-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include "UsbGadget.h"
using ::aidl::android::hardware::usb::gadget::UsbGadget;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<UsbGadget> usbgadget = ndk::SharedRefBase::make<UsbGadget>();
const std::string instance = std::string() + UsbGadget::descriptor + "/default";
binder_status_t status = AServiceManager_addService(usbgadget->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
ABinderProcess_joinThreadPool();
return -1;
}

View File

@@ -9,10 +9,8 @@ ro.hardware.audio.primary=rpi
# 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
@@ -39,7 +37,7 @@ media.settings.xml=/vendor/etc/media_profiles_V1_0.xml
ro.hardware.camera=libcamera
# CEC
persist.hdmi.cec_device=cec0
ro.hdmi.cec_device=cec0
ro.hdmi.device_type=4
# Display
@@ -52,7 +50,7 @@ persist.ffmpeg_codec2.v4l2.h264=false
persist.ffmpeg_codec2.v4l2.h265=true
# Graphics
ro.hardware.egl=mesa
ro.hardware.hwcomposer=drm
ro.hardware.vulkan=broadcom
ro.opengles.version=196609
vendor.hwc.drm.ctm=DRM_OR_IGNORE
@@ -69,18 +67,9 @@ ro.lmk.medium=800
ro.lmk.upgrade_pressure=100
ro.lmk.use_minfree_levels=true
# Lockscreen
ro.lockscreen.disable.default=true
# Media
debug.stagefright.c2inputsurface=-1
# MGLRU
persist.device_config.mglru_native.lru_gen_config=core
# Storage
persist.sys.fuse.backup.external_volume_backup=false
# V4L2
debug.stagefright.c2-poolmask=0xf50000
persist.v4l2_codec2.rank.decoder=128
@@ -91,6 +80,3 @@ ro.vendor.v4l2_codec2.encode_concurrent_instances=8
# Wifi
wifi.interface=wlan0
# Window extensions
persist.settings.large_screen_opt.enabled=true

View File

@@ -1,13 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2009-2012 Broadcom Corporation
Copyright (C) 2021-2022 KonstaKANG
<!-- Copyright 2022 The Android Open Source Project
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
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,
@@ -16,9 +14,8 @@
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>
<!-- This is the standard feature indicating that the device has a Vulkan
driver that supports API version 1.2 (0x00402000) -->
<permissions>
<feature name="android.hardware.vulkan.version" version="4202496" />
</permissions>