6db4831e98
Android 14
270 lines
6.1 KiB
C
270 lines
6.1 KiB
C
/*
|
|
* Copyright (C) 2020, Samsung Electronics Co. Ltd. All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#include "../comm/shub_iio.h"
|
|
#include "../sensorhub/shub_device.h"
|
|
#include "../sensormanager/shub_sensor_type.h"
|
|
#include "../sensormanager/shub_sensor_manager.h"
|
|
#include "shub_dev_core.h"
|
|
#include "shub_utility.h"
|
|
|
|
#include <linux/mutex.h>
|
|
#include <linux/device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/notifier.h>
|
|
|
|
#define FILE_MANAGER 0xFB
|
|
enum {
|
|
FM_READ = 0,
|
|
FM_WRITE,
|
|
FM_REMOVE,
|
|
FM_READY,
|
|
};
|
|
|
|
static BLOCKING_NOTIFIER_HEAD(fm_ready_notifier_list);
|
|
struct mutex fm_ready_notifier_mutex;
|
|
struct work_struct fm_nofifier_work;
|
|
|
|
struct mutex fm_mutex;
|
|
struct completion fm_done;
|
|
bool is_fm_ready;
|
|
|
|
struct fm_msg_t {
|
|
int32_t result;
|
|
int32_t rx_buf_size;
|
|
char rx_buf[PAGE_SIZE];
|
|
int32_t tx_buf_size;
|
|
char tx_buf[PAGE_SIZE];
|
|
bool wait;
|
|
};
|
|
|
|
struct fm_msg_t fm_msg;
|
|
|
|
static void fm_notifier_work_func(struct work_struct *work)
|
|
{
|
|
mutex_lock(&fm_ready_notifier_mutex);
|
|
is_fm_ready = true;
|
|
shub_infof("");
|
|
blocking_notifier_call_chain(&fm_ready_notifier_list, FM_READY, NULL);
|
|
mutex_unlock(&fm_ready_notifier_mutex);
|
|
}
|
|
|
|
static void file_manager_ready(void)
|
|
{
|
|
shub_infof("");
|
|
shub_queue_work(&fm_nofifier_work);
|
|
}
|
|
|
|
void unregister_file_manager_ready_callback(struct notifier_block *nb)
|
|
{
|
|
mutex_lock(&fm_ready_notifier_mutex);
|
|
blocking_notifier_chain_unregister(&fm_ready_notifier_list, nb);
|
|
mutex_unlock(&fm_ready_notifier_mutex);
|
|
}
|
|
|
|
void register_file_manager_ready_callback(struct notifier_block *nb)
|
|
{
|
|
mutex_lock(&fm_ready_notifier_mutex);
|
|
blocking_notifier_chain_register(&fm_ready_notifier_list, nb);
|
|
shub_infof("");
|
|
if (is_fm_ready)
|
|
nb->notifier_call(nb, FM_READY, NULL);
|
|
mutex_unlock(&fm_ready_notifier_mutex);
|
|
}
|
|
|
|
static int _shub_file_rw(char type, bool wait)
|
|
{
|
|
char send_buf[2];
|
|
int ret, result = 0;
|
|
|
|
send_buf[0] = FILE_MANAGER;
|
|
send_buf[1] = type;
|
|
|
|
fm_msg.wait = wait;
|
|
|
|
init_completion(&fm_done);
|
|
|
|
shub_report_sensordata(SENSOR_TYPE_SENSORHUB, get_current_timestamp(), send_buf, sizeof(send_buf));
|
|
|
|
if (wait) {
|
|
ret = wait_for_completion_timeout(&fm_done, msecs_to_jiffies(1000));
|
|
if (!ret) {
|
|
shub_errf("time out");
|
|
result = -EIO;
|
|
} else {
|
|
result = fm_msg.result;
|
|
}
|
|
} else {
|
|
ret = wait_for_completion_timeout(&fm_done, msecs_to_jiffies(500));
|
|
if (!ret)
|
|
shub_errf("write_no_wait time out");
|
|
}
|
|
|
|
if (!ret) {
|
|
memset(fm_msg.tx_buf, 0, fm_msg.tx_buf_size);
|
|
fm_msg.tx_buf_size = 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static int _shub_file_write(char *path, char *buf, int buf_len, long long pos, bool wait)
|
|
{
|
|
int ret;
|
|
|
|
if (!is_fm_ready)
|
|
return -ENODEV;
|
|
|
|
mutex_lock(&fm_mutex);
|
|
fm_msg.tx_buf_size =
|
|
snprintf(fm_msg.tx_buf, sizeof(fm_msg.tx_buf), "%s,%d,%lld,%d,", path, buf_len, pos, wait);
|
|
memcpy(&fm_msg.tx_buf[fm_msg.tx_buf_size], buf, buf_len);
|
|
fm_msg.tx_buf_size += buf_len;
|
|
ret = _shub_file_rw(FM_WRITE, wait);
|
|
mutex_unlock(&fm_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int shub_file_write_no_wait(char *path, char *buf, int buf_len, long long pos)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = _shub_file_write(path, buf, buf_len, pos, false);
|
|
|
|
return (ret < 0) ? ret : buf_len;
|
|
}
|
|
|
|
int shub_file_write(char *path, char *buf, int buf_len, long long pos)
|
|
{
|
|
return _shub_file_write(path, buf, buf_len, pos, true);
|
|
}
|
|
|
|
int shub_file_read(char *path, char *buf, int buf_len, long long pos)
|
|
{
|
|
int ret;
|
|
|
|
if (!is_fm_ready)
|
|
return -ENODEV;
|
|
|
|
mutex_lock(&fm_mutex);
|
|
fm_msg.tx_buf_size = snprintf(fm_msg.tx_buf, sizeof(fm_msg.tx_buf), "%s,%d,%lld", path, buf_len, pos);
|
|
ret = _shub_file_rw(FM_READ, true);
|
|
if (ret > 0)
|
|
memcpy(buf, fm_msg.rx_buf, buf_len);
|
|
mutex_unlock(&fm_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int shub_file_remove(char *path)
|
|
{
|
|
int ret;
|
|
|
|
if (!is_fm_ready)
|
|
return -ENODEV;
|
|
|
|
mutex_lock(&fm_mutex);
|
|
fm_msg.tx_buf_size = snprintf(fm_msg.tx_buf, sizeof(fm_msg.tx_buf), "%s", path);
|
|
ret = _shub_file_rw(FM_REMOVE, true);
|
|
mutex_unlock(&fm_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t shub_file_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
if (fm_msg.tx_buf_size == 0)
|
|
return -EINVAL;
|
|
|
|
memcpy(buf, fm_msg.tx_buf, fm_msg.tx_buf_size);
|
|
if (!fm_msg.wait)
|
|
complete(&fm_done);
|
|
return fm_msg.tx_buf_size;
|
|
}
|
|
|
|
ssize_t shub_file_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
|
{
|
|
if (size < 1) {
|
|
shub_errf("error %d", (int)size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!is_fm_ready) {
|
|
if (buf[0] == FM_READY)
|
|
file_manager_ready();
|
|
|
|
} else {
|
|
if (size < 5) {
|
|
shub_errf("error %d", (int)size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
memset(fm_msg.tx_buf, 0, fm_msg.tx_buf_size);
|
|
fm_msg.tx_buf_size = 0;
|
|
|
|
memset(fm_msg.rx_buf, 0, PAGE_SIZE);
|
|
memcpy(&fm_msg.result, &buf[1], sizeof(int32_t));
|
|
if (buf[0] == FM_READ && fm_msg.result > 0) {
|
|
fm_msg.rx_buf_size = fm_msg.result;
|
|
memcpy(fm_msg.rx_buf, &buf[5], fm_msg.rx_buf_size);
|
|
}
|
|
|
|
complete(&fm_done);
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
static DEVICE_ATTR(shub_file, 0660, shub_file_show, shub_file_store);
|
|
static struct device_attribute *shub_attrs[] = {
|
|
&dev_attr_shub_file,
|
|
NULL,
|
|
};
|
|
|
|
int init_file_manager(void)
|
|
{
|
|
int ret;
|
|
struct shub_data_t *data = get_shub_data();
|
|
|
|
mutex_init(&fm_mutex);
|
|
mutex_init(&fm_ready_notifier_mutex);
|
|
INIT_WORK(&fm_nofifier_work, fm_notifier_work_func);
|
|
|
|
ret = sensor_device_create(&data->sysfs_dev, data, "ssp_sensor");
|
|
if (ret < 0) {
|
|
shub_errf("fail to creat ssp_sensor device");
|
|
return ret;
|
|
}
|
|
|
|
ret = add_sensor_device_attr(data->sysfs_dev, shub_attrs);
|
|
if (ret < 0)
|
|
shub_errf("fail to add shub device attr");
|
|
|
|
return ret;
|
|
}
|
|
|
|
void remove_file_manager(void)
|
|
{
|
|
struct shub_data_t *data = get_shub_data();
|
|
|
|
cancel_work_sync(&fm_nofifier_work);
|
|
mutex_destroy(&fm_ready_notifier_mutex);
|
|
mutex_destroy(&fm_mutex);
|
|
remove_sensor_device_attr(data->sysfs_dev, shub_attrs);
|
|
sensor_device_destroy(data->sysfs_dev);
|
|
}
|
|
|