blob: 0115b91169c7dcbebc0d6dcc7e440cc1028e9bc3 [file] [log] [blame]
/*
* Copyright (C) 2022 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "main.h"
#include "display.h"
#include "nanohub_exports.h"
#include <asm-generic/errno.h>
#define NANOHUB_DISPLAY_COMMAND_VERSION 0x01
static DEFINE_MUTEX(nanohub_display_mutex);
static DECLARE_COMPLETION(message_callback);
static int display_state;
static bool allow_read_mcu_disp_state_once = false;
ssize_t nanohub_pin_display_select_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct nanohub_data *data = dev_get_drvdata(dev);
const struct nanohub_platform_data *pdata = data->pdata;
return scnprintf(buf, PAGE_SIZE, "%d\n",
gpio_get_value(pdata->display_select_gpio));
}
ssize_t nanohub_pin_display_select_set(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct nanohub_data *data = dev_get_drvdata(dev);
const struct nanohub_platform_data *pdata = data->pdata;
if (count >= 1 && buf[0] == '0') {
allow_read_mcu_disp_state_once = false;
gpio_set_value(pdata->display_select_gpio, 0);
} else if (count >= 1 && buf[0] == '1') {
if (gpio_get_value(pdata->display_select_gpio) == 0)
allow_read_mcu_disp_state_once = true;
gpio_set_value(pdata->display_select_gpio, 1);
}
return count;
}
ssize_t nanohub_get_display_state(struct device *dev, struct device_attribute *attr, char *buf)
{
struct nanohub_data *data = dev_get_drvdata(dev);
int display_state = nanohub_query_display_state_internal(data, true);
return scnprintf(buf, PAGE_SIZE, "%d", display_state);
}
ssize_t nanohub_get_display_state_no_check(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct nanohub_data *data = dev_get_drvdata(dev);
int display_state = nanohub_query_display_state_internal(data, false);
return scnprintf(buf, PAGE_SIZE, "%d", display_state);
}
#define NANOHUB_DISPLAY_GET_STATE_TIMEOUT_MS 100
enum nanohub_display_command_type {
NANOHUB_DISPLAY_COMMAND_GET_STATE = 0x06,
NANOHUB_DISPLAY_COMMAND_GET_STATE_NO_CHECK = 0x07,
};
static void on_message_received(const char *buffer, size_t length)
{
if (length == 3 && buffer[0] == NANOHUB_DISPLAY_COMMAND_VERSION &&
buffer[1] == NANOHUB_DISPLAY_COMMAND_GET_STATE) {
display_state = buffer[2];
}
complete(&message_callback);
}
int nanohub_query_display_state_internal(struct nanohub_data *data, bool check_ownership)
{
const char message[] = { NANOHUB_DISPLAY_COMMAND_VERSION,
check_ownership ? NANOHUB_DISPLAY_COMMAND_GET_STATE :
NANOHUB_DISPLAY_COMMAND_GET_STATE_NO_CHECK };
long ret;
if (check_ownership) {
const struct nanohub_platform_data *pdata;
if (unlikely(data == NULL))
return -EINVAL;
pdata = data->pdata;
if (gpio_get_value(pdata->display_select_gpio) == 1)
return MCU_DISPLAY_NONE;
} else {
if (allow_read_mcu_disp_state_once)
allow_read_mcu_disp_state_once = false;
else
return MCU_DISPLAY_NONE;
}
mutex_lock(&nanohub_display_mutex);
nanohub_register_listener(NANOHUB_DISPLAY_KERNEL_CHANNEL_ID, on_message_received);
reinit_completion(&message_callback);
display_state = -ENODATA;
nanohub_send_message(NANOHUB_DISPLAY_CHANNEL_ID, message, sizeof(message));
ret = wait_for_completion_interruptible_timeout(
&message_callback, msecs_to_jiffies(NANOHUB_DISPLAY_GET_STATE_TIMEOUT_MS));
nanohub_unregister_listener(NANOHUB_DISPLAY_KERNEL_CHANNEL_ID);
mutex_unlock(&nanohub_display_mutex);
if (ret <= 0) {
pr_err("nanohub : failed to query disp, ret = %d\n", ret);
if (ret == 0)
return -ETIMEDOUT;
else
return ret;
}
return display_state;
}