universal7885: fm-aidl: Move ioctl code to hal

This commit is contained in:
roynatech2544 2022-10-06 09:55:12 +00:00
commit 839dc3ae4c
8 changed files with 325 additions and 506 deletions

View file

@ -0,0 +1,30 @@
cc_library_static {
name: "libfm_slsi-impl",
cflags: [
"-Wno-unused-parameter",
],
srcs: [
"FM_Device_ctl.cpp",
"FM_AudioRoute_ctl.cpp",
],
export_include_dirs: ["public"],
defaults: ["eureka_defaults"],
shared_libs: [
"libhidlbase",
"liblog",
"libutils",
"audioflinger-aidl-cpp",
"audiopolicy-aidl-cpp",
"audiopolicy-types-aidl-cpp",
"libaudiofoundation",
"libaudioutils",
"libaudioclient",
"libutils",
"libaudiopolicy",
"libaudiomanager",
],
header_libs: [
"libaudioclient_headers",
"jni_headers",
],
}

View file

@ -0,0 +1,38 @@
/*
* Copyright 2021 Soo Hwan Na "Royna"
*
* 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 <jni.h>
#include <media/AudioSystem.h>
#include <media/IAudioFlinger.h>
#define FM_FAILURE (-1)
#define FM_SUCCESS 0
#define IOHANDLE 13
using namespace android;
extern "C" JNIEXPORT jboolean JNICALL
Java_com_eurekateam_fmradio_NativeFMInterface_setAudioRoute(
__unused JNIEnv *env, __unused jobject thiz, jboolean speaker) {
const sp<IAudioFlinger> &af = AudioSystem::get_audio_flinger();
if (af == 0)
return PERMISSION_DENIED;
if (speaker) {
af->setParameters(IOHANDLE, String8("routing=2"));
} else {
af->setParameters(IOHANDLE, String8("routing=8"));
}
return FM_SUCCESS;
}

View file

@ -0,0 +1,293 @@
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <stdint.h>
#include <cstring>
#include <unistd.h>
#include <cerrno>
#include <iostream>
#include "S610_FMRadio.h"
#include "V4L2_4_4_API.h"
#include <algorithm>
#include <jni.h>
#include <memory>
#include <vector>
#include <thread>
namespace fm_radio_slsi {
constexpr const int TRACK_SIZE = 30;
static bool FMThread = false;
int open_device(void) {
int fd;
if ((fd = open("/dev/radio0", O_RDWR | O_CLOEXEC)) < 0) {
printf("Cannot open /dev/radio0.\n");
return -1;
}
return fd;
}
int get_frequency(const int fd, int64_t *channel) {
struct v4l2_frequency freq {};
int ret;
freq.tuner = 0;
freq.type = V4L2_TUNER_RADIO;
ret = ioctl(fd, VIDIOC_G_FREQUENCY, &freq);
if (ret < 0)
return FM_FAILURE;
*channel = static_cast<int64_t>(freq.frequency) / 16000;
return FM_SUCCESS;
}
int set_frequency(const int fd, int64_t channel) {
struct v4l2_frequency freq {};
int ret;
freq.tuner = 0;
freq.type = V4L2_TUNER_RADIO;
freq.frequency = (unsigned int)channel * 16000;
ret = ioctl(fd, VIDIOC_S_FREQUENCY, &freq);
if (ret < 0) {
printf("FmRadioController: failed to set frequency\n");
return FM_FAILURE;
}
return FM_SUCCESS;
}
static int set_control(const int fd, unsigned int id, int64_t val) {
struct v4l2_control ctrl {};
int ret;
ctrl.id = id;
if (val)
ctrl.value = static_cast<unsigned int>(val);
else
ctrl.value = 0;
ret = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
if (ret < 0) {
return FM_FAILURE;
}
return FM_SUCCESS;
}
int seek_frequency(int fd, unsigned int upward,
unsigned int wrap_around,
unsigned int spacing) {
struct v4l2_hw_freq_seek seek {};
int ret;
seek.tuner = 0;
seek.type = V4L2_TUNER_RADIO;
seek.seek_upward = upward;
seek.wrap_around = wrap_around;
seek.spacing = spacing;
ret = ioctl(fd, VIDIOC_S_HW_FREQ_SEEK, &seek);
if (ret < 0) {
return FM_FAILURE;
}
return FM_SUCCESS;
}
int channel_search(const int fd, unsigned int upward,
unsigned int wrap_around,
unsigned int spacing, int64_t *channel) {
int ret;
ret = set_control(fd, V4L2_CID_S610_SEEK_MODE,
FM_TUNER_AUTONOMOUS_SEARCH_MODE);
if (ret < 0)
return ret;
ret = seek_frequency(fd, upward, wrap_around, spacing);
if (ret < 0)
return ret;
ret = get_frequency(fd, channel);
if (ret < 0)
return ret;
return ret;
}
int set_mute(const int fd, bool mute) {
int ret = set_control(fd, V4L2_CID_AUDIO_MUTE, !mute);
if (ret < 0) {
return FM_FAILURE;
}
return FM_SUCCESS;
}
int set_volume(int fd, int volume /* 1 ~ 15 */) {
int ret = set_control(fd, V4L2_CID_AUDIO_VOLUME, volume);
if (ret < 0) {
return FM_FAILURE;
}
return FM_SUCCESS;
}
std::unique_ptr<int64_t[]> get_freqs(const int fd) {
set_mute(fd, true);
auto map = std::vector<int64_t>();
for (int i = 0; i < TRACK_SIZE; i++) {
int64_t found = 0;
channel_search(fd, 1, 0, FM_CHANNEL_SPACING_50KHZ, &found);
for (auto k : map) {
if (k == found)
continue;
}
map.push_back(found);
}
auto ptr = std::make_unique<int64_t[]>(map.size());
for (unsigned long i = 0; i < map.size(); i++) {
ptr[i] = map[i];
}
set_mute(fd, false);
return std::move(ptr);
}
static int fm_poll(int fd, struct pollfd *poll_fd) {
int ret;
poll_fd->fd = fd;
poll_fd->events = POLLIN;
poll_fd->revents = 0;
ret = poll(poll_fd, 1, 360);
if (ret > 0) {
if (poll_fd->revents & POLLIN) {
return FM_SUCCESS;
}
return FM_FAILURE;
}
if (!ret) {
return FM_FAILURE;
}
return FM_FAILURE - 1;
}
static int fm_read(int fd, unsigned char *buf) {
int ret;
ret = read(fd, buf, FM_RADIO_RDS_DATA_MAX);
if (ret < 0) {
printf("FmRadioController: failed to read\n");
return FM_FAILURE;
}
return ret;
}
static void fm_thread(int fd) {
struct pollfd radio_poll {};
unsigned char read_buf[FM_RADIO_RDS_DATA_MAX];
int ret;
while (FMThread) {
ret = fm_poll(fd, &radio_poll);
if (ret < 0) {
if (ret < FM_FAILURE)
break;
else
continue;
}
ret = fm_read(fd, read_buf);
if (ret < 0)
break;
}
}
void fm_thread_set(const int fd, const bool enable) {
FMThread = enable;
if (enable) fm_thread(fd);
}
unsigned int get_upperband_limit(int fd) {
int ret;
struct v4l2_tuner tuner {};
unsigned int freq;
tuner.index = 0;
ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
if (ret < 0) {
return FM_FAILURE;
} else {
freq = (tuner.rangehigh / 16000);
return freq;
}
}
unsigned int get_lowerband_limit(int fd) {
int ret;
unsigned int freq;
struct v4l2_tuner tuner {};
tuner.index = 0;
ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
if (ret < 0) {
return FM_FAILURE;
} else {
freq = (tuner.rangelow / 16000);
return freq;
}
}
int64_t get_rmssi(int fd) {
struct v4l2_tuner tuner {};
int ret;
int64_t rmssi;
tuner.index = 0;
tuner.signal = 0;
ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
if (ret < 0) {
ret = FM_FAILURE;
} else {
rmssi = tuner.signal;
ret = rmssi;
}
return ret;
}
int set_rssi(int fd, int64_t rssi) {
int ret = set_control(fd, V4L2_CID_S610_RSSI_TH, rssi);
if (ret < 0) {
return FM_FAILURE;
}
return FM_SUCCESS;
}
void bootctrl(const int fd) {
set_control(fd, V4L2_CID_S610_IF_COUNT1, 4800); // SetIFCount 1
set_control(fd, V4L2_CID_S610_IF_COUNT2, 5600); // SetIFCount 2
set_control(fd, V4L2_CID_S610_SOFT_STEREO_BLEND,
3172); // Set Soft Stereo Blend
set_control(fd, V4L2_CID_S610_SOFT_MUTE_COEFF,
16); // SetSoftMuteCoeff
set_control(fd, V4L2_CID_S610_CH_BAND,
S610_BAND_FM); // Set Band (To FM)
set_control(fd, V4L2_CID_S610_CH_SPACING,
FM_CHANNEL_SPACING_50KHZ); // Spacing 5kHz
set_control(fd, V4L2_CID_S610_RDS_ON, FM_RDS_ENABLE); // RDS on
}
void stop_search(const int fd) {
set_control(fd, V4L2_CID_S610_SEEK_CANCEL, 1);
}
}

View file

@ -0,0 +1,56 @@
#define FM_FAILURE (-1)
#define FM_SUCCESS 0
#define V4L2_CID_USER_S610_BASE (0x00980900 + 0x1070)
enum s610_ctrl_id {
V4L2_CID_S610_CH_SPACING = (V4L2_CID_USER_S610_BASE + 0x01),
V4L2_CID_S610_CH_BAND = (V4L2_CID_USER_S610_BASE + 0x02),
V4L2_CID_S610_SOFT_STEREO_BLEND = (V4L2_CID_USER_S610_BASE + 0x03),
V4L2_CID_S610_SOFT_STEREO_BLEND_COEFF = (V4L2_CID_USER_S610_BASE + 0x04),
V4L2_CID_S610_SOFT_MUTE_COEFF = (V4L2_CID_USER_S610_BASE + 0x5),
V4L2_CID_S610_RSSI_CURR = (V4L2_CID_USER_S610_BASE + 0x06),
V4L2_CID_S610_SNR_CURR = (V4L2_CID_USER_S610_BASE + 0x07),
V4L2_CID_S610_SEEK_CANCEL = (V4L2_CID_USER_S610_BASE + 0x08),
V4L2_CID_S610_SEEK_MODE = (V4L2_CID_USER_S610_BASE + 0x09),
V4L2_CID_S610_RDS_ON = (V4L2_CID_USER_S610_BASE + 0x0A),
V4L2_CID_S610_IF_COUNT1 = (V4L2_CID_USER_S610_BASE + 0x0B),
V4L2_CID_S610_IF_COUNT2 = (V4L2_CID_USER_S610_BASE + 0x0C),
V4L2_CID_S610_RSSI_TH = (V4L2_CID_USER_S610_BASE + 0x0D),
V4L2_CID_S610_KERNEL_VER = (V4L2_CID_USER_S610_BASE + 0x0E),
V4L2_CID_S610_SOFT_STEREO_BLEND_REF = (V4L2_CID_USER_S610_BASE + 0x0F),
V4L2_CID_S610_REG_RW_ADDR = (V4L2_CID_USER_S610_BASE + 0x10),
V4L2_CID_S610_REG_RW = (V4L2_CID_USER_S610_BASE + 0x11),
};
/* Tunner modes */
enum fm_tuner_mode {
FM_TUNER_STOP_SEARCH_MODE = 0,
FM_TUNER_PRESET_MODE = 1,
FM_TUNER_AUTONOMOUS_SEARCH_MODE = 2,
FM_TUNER_AUTONOMOUS_SEARCH_MODE_NEXT = 10
};
/* channel spacing */
enum fm_channel_spacing {
FM_CHANNEL_SPACING_50KHZ = 1,
FM_CHANNEL_SPACING_100KHZ = 2,
FM_CHANNEL_SPACING_200KHZ = 4
};
/* Mute modes */
enum fm_mute_mode { FM_MUTE_ON = 0, FM_MUTE_OFF = 1, FM_MUTE_ATTENUATE = 2 };
/* FM RDS modes */
enum fm_rds_mode { FM_RDS_DISABLE = 0, FM_RDS_ENABLE = 1 };
#define FM_RADIO_RDS_DATA_MAX 48
enum s610_freq_bands {
S610_BAND_FM = 0,
S610_BAND_AM = 1,
};
enum s610_aud_mode {
S610_AUD_ENABLE = 1,
S610_AUD_DISABLE = 0,
};

View file

@ -0,0 +1,124 @@
#include <cstdint>
typedef u_int8_t __u8;
typedef int32_t __s32;
typedef u_int32_t __u32;
struct v4l2_tuner {
__u32 index;
__u8 name[32];
__u32 type; /* enum v4l2_tuner_type */
__u32 capability;
__u32 rangelow;
__u32 rangehigh;
__u32 rxsubchans;
__u32 audmode;
__s32 signal;
__s32 afc;
__u32 reserved[4];
};
struct v4l2_frequency {
__u32 tuner;
__u32 type; /* enum v4l2_tuner_type */
__u32 frequency;
__u32 reserved[8];
};
struct v4l2_hw_freq_seek {
__u32 tuner;
__u32 type; /* enum v4l2_tuner_type */
__u32 seek_upward;
__u32 wrap_around;
__u32 spacing;
__u32 rangelow;
__u32 rangehigh;
__u32 reserved[5];
};
enum v4l2_tuner_type {
V4L2_TUNER_RADIO = 1,
V4L2_TUNER_ANALOG_TV = 2,
V4L2_TUNER_DIGITAL_TV = 3,
V4L2_TUNER_SDR = 4,
V4L2_TUNER_RF = 5,
};
struct v4l2_control {
__u32 id;
__s32 value;
};
/**
* struct v4l2_capability - Describes V4L2 device caps returned by
* VIDIOC_QUERYCAP
*
* @driver: name of the driver module (e.g. "bttv")
* @card: name of the card (e.g. "Hauppauge WinTV")
* @bus_info: name of the bus (e.g. "PCI:" + pci_name(pci_dev) )
* @version: KERNEL_VERSION
* @capabilities: capabilities of the physical device as a whole
* @device_caps: capabilities accessed via this particular device (node)
* @reserved: reserved fields for future extensions
*/
struct v4l2_capability {
__u8 driver[16];
__u8 card[32];
__u8 bus_info[32];
__u32 version;
__u32 capabilities;
__u32 device_caps;
__u32 reserved[3];
};
/*
* T I M E C O D E
*/
struct v4l2_timecode {
__u32 type;
__u32 flags;
__u8 frames;
__u8 seconds;
__u8 minutes;
__u8 hours;
__u8 userbits[4];
};
struct v4l2_buffer {
__u32 index;
__u32 type;
__u32 bytesused;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
/* memory location */
__u32 memory;
union {
__u32 offset;
uint64_t userptr;
struct v4l2_plane *planes;
__s32 fd;
} m;
__u32 length;
__u32 reserved2;
__u32 reserved;
};
#define V4L2_TUNER_MODE_MONO 0x0000
#define V4L2_TUNER_MODE_STEREO 0x0001
// Ioctl
#define VIDIOC_G_FREQUENCY _IOWR('V', 56, struct v4l2_frequency)
#define VIDIOC_S_FREQUENCY _IOW('V', 57, struct v4l2_frequency)
#define VIDIOC_G_TUNER _IOWR('V', 29, struct v4l2_tuner)
#define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek)
#define VIDIOC_S_TUNER _IOW('V', 30, struct v4l2_tuner)
#define VIDIOC_S_CTRL _IOWR('V', 28, struct v4l2_control)
#define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability)
#define VIDIOC_G_CTRL _IOWR('V', 27, struct v4l2_control)
#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */
#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE + 5)
#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE + 9)

View file

@ -0,0 +1,24 @@
#pragma once
#include <memory>
namespace fm_radio_slsi {
int open_device(void);
int get_frequency(const int fd, int64_t *channel);
int set_frequency(const int fd, int64_t channel);
int seek_frequency(int fd, unsigned int upward, unsigned int wrap_around,
unsigned int spacing);
int channel_search(const int fd, unsigned int upward, unsigned int wrap_around,
unsigned int spacing, int64_t *channel);
int set_mute(const int fd, bool mute);
int set_volume(int fd, int volume);
std::unique_ptr<int64_t[]> get_freqs(const int fd);
void fm_thread_set(const int fd, const bool enable);
unsigned int get_upperband_limit(int fd);
unsigned int get_lowerband_limit(int fd);
int64_t get_rmssi(int fd);
int set_rssi(int fd, int64_t rssi);
void bootctrl(const int fd);
void stop_search(const int fd);
} // namespace fm_radio_slsi