maru_light.o \
maru_proxi.o \
maru_rotation_vector.o \
- maru_haptic.o
+ maru_haptic.o \
+ maru_pressure.o \
+ maru_uv.o \
+ maru_hrm.o
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/limits.h>
#include "maru_virtio_sensor.h"
static struct device *l_accel_sensor_device;
#endif
+#define GRAVITY_CHANGE_UNIT 15322
+static short sensor_convert_data(int number)
+{
+ int temp;
+ temp = number / 64;
+ temp = temp * (SHRT_MAX / 2);
+ temp = temp / GRAVITY_CHANGE_UNIT;
+ return (short)temp;
+}
+
static void maru_accel_input_work_func(struct work_struct *work) {
int poll_time = 200000000;
int enable = 0;
int ret = 0;
int accel_x, accel_y, accel_z;
+ short raw_x, raw_y, raw_z;
char sensor_data[__MAX_BUF_SENSOR];
struct maru_accel_data *data = container_of((struct delayed_work *)work,
struct maru_accel_data, work);
mutex_unlock(&data->data_mutex);
if (!ret) {
sscanf(sensor_data, "%d,%d,%d", &accel_x, &accel_y, &accel_z);
- LOG(1, "accel_set %d, %d, %d", accel_x, accel_y, accel_z);
-
- input_report_rel(data->input_data, REL_RX, accel_x);
- input_report_rel(data->input_data, REL_RY, accel_y);
- input_report_rel(data->input_data, REL_RZ, accel_z);
+ LOG(1, "accel_set act %d, %d, %d", accel_x, accel_y, accel_z);
+ raw_x = sensor_convert_data(accel_x);
+ raw_y = sensor_convert_data(accel_y);
+ raw_z = sensor_convert_data(accel_z);
+ LOG(1, "accel_set raw %d, %d, %d", raw_x, raw_y, raw_z);
+
+ if (raw_x == 0) {
+ raw_x = 1;
+ }
+
+ if (raw_y == 0) {
+ raw_y = 1;
+ }
+
+ if (raw_z == 0) {
+ raw_z = 1;
+ }
+
+ input_report_rel(data->input_data, REL_X, raw_x);
+ input_report_rel(data->input_data, REL_Y, raw_y);
+ input_report_rel(data->input_data, REL_Z, raw_z);
input_sync(data->input_data);
}
}
{
int delay = 0;
int ret = 0;
- int enable = 0;
char sensor_data [__MAX_BUF_SENSOR];
- memset(sensor_data, 0, __MAX_BUF_SENSOR);
+ memset(sensor_data, 0, sizeof(sensor_data));
ret = get_sensor_data(sensor_type_accel_delay, sensor_data);
if (ret) {
}
delay = sensor_atoi(sensor_data);
-
- ret = get_sensor_data(sensor_type_accel_enable, sensor_data);
- if (ret) {
- ERR("failed to get initial enable");
- return ret;
- }
-
- enable = sensor_atoi(sensor_data);
-
if (delay < 0) {
ERR("weird value is set initial delay");
return ret;
atomic_set(&data->poll_delay, delay);
- if (enable) {
- atomic_set(&data->enable, 1);
- schedule_delayed_work(&data->work, 0);
- }
+ memset(sensor_data, 0, sizeof(sensor_data));
+ sensor_data[0] = '0';
+
+ set_sensor_data(sensor_type_accel_enable, sensor_data);
+ atomic_set(&data->enable, 0);
return ret;
}
set_bit(EV_REL, input_data->evbit);
set_bit(EV_SYN, input_data->evbit);
- input_set_capability(input_data, EV_REL, REL_RX);
- input_set_capability(input_data, EV_REL, REL_RY);
- input_set_capability(input_data, EV_REL, REL_RZ);
+ input_set_capability(input_data, EV_REL, REL_X);
+ input_set_capability(input_data, EV_REL, REL_Y);
+ input_set_capability(input_data, EV_REL, REL_Z);
data->input_data = input_data;
static struct device *l_geo_sensor_device;
#endif
+static short sensor_convert_data(int number)
+{
+ return (short) ((number * 5) / 3); // divided by 0.6
+}
+
static void maru_geo_input_work_func(struct work_struct *work) {
int poll_time = 200000000;
int enable = 0;
int ret = 0;
- int geo_x, geo_y, geo_z, hdst;
+ int geo_x, geo_y, geo_z, hdst = 4;
+ short raw_x, raw_y, raw_z;
char sensor_data[__MAX_BUF_SENSOR];
struct maru_geo_data *data = container_of((struct delayed_work *)work,
struct maru_geo_data, work);
if (enable) {
mutex_lock(&data->data_mutex);
- ret = get_sensor_data(sensor_type_tilt, sensor_data);
+ ret = get_sensor_data(sensor_type_mag, sensor_data);
mutex_unlock(&data->data_mutex);
if (!ret) {
- sscanf(sensor_data, "%d %d %d %d", &geo_x, &geo_y, &geo_z, &hdst);
- LOG(1, "geo_set %d, %d, %d, %d", geo_x, geo_y, geo_z, hdst);
-
- input_report_rel(data->input_data, REL_RX, geo_x);
- input_report_rel(data->input_data, REL_RY, geo_y);
- input_report_rel(data->input_data, REL_RZ, geo_z);
+ sscanf(sensor_data, "%d %d %d", &geo_x, &geo_y, &geo_z);
+ LOG(1, "geo_set act %d, %d, %d", geo_x, geo_y, geo_z);
+ raw_x = sensor_convert_data(geo_x);
+ raw_y = sensor_convert_data(geo_y);
+ raw_z = sensor_convert_data(geo_z);
+ LOG(1, "geo_set raw %d, %d, %d, %d", raw_x, raw_y, raw_z, hdst);
+
+ if (raw_x == 0) {
+ raw_x = 1;
+ }
+
+ if (raw_y == 0) {
+ raw_y = 1;
+ }
+
+ if (raw_z == 0) {
+ raw_z = 1;
+ }
+
+ input_report_rel(data->input_data, REL_RX, raw_x);
+ input_report_rel(data->input_data, REL_RY, raw_y);
+ input_report_rel(data->input_data, REL_RZ, raw_z);
input_report_rel(data->input_data, REL_HWHEEL, hdst);
input_sync(data->input_data);
}
{
int delay = 0;
int ret = 0;
- int enable = 0;
char sensor_data [__MAX_BUF_SENSOR];
memset(sensor_data, 0, __MAX_BUF_SENSOR);
}
delay = sensor_atoi(sensor_data);
-
- ret = get_sensor_data(sensor_type_geo_enable, sensor_data);
- if (ret) {
- ERR("failed to get initial enable");
- return ret;
- }
-
- enable = sensor_atoi(sensor_data);
-
if (delay < 0) {
ERR("weird value is set initial delay");
return ret;
atomic_set(&data->poll_delay, delay);
- if (enable) {
- atomic_set(&data->enable, 1);
- schedule_delayed_work(&data->work, 0);
- }
+ memset(sensor_data, 0, sizeof(sensor_data));
+ sensor_data[0] = '0';
+ set_sensor_data(sensor_type_geo_enable, sensor_data);
+ atomic_set(&data->enable, 0);
return ret;
}
static struct device *l_gyro_sensor_device;
#endif
+static int gyro_adjust_x = 1;
+static int gyro_adjust_y = 1;
+static int gyro_adjust_z = 1;
+
static void maru_gyro_input_work_func(struct work_struct *work) {
int poll_time = 200000000;
mutex_unlock(&data->data_mutex);
if (!ret) {
sscanf(sensor_data, "%d,%d,%d", &gyro_x, &gyro_y, &gyro_z);
- LOG(1, "gyro_set %d, %d, %d", gyro_x, gyro_y, gyro_z);
+ LOG(1, "gyro_set act %d, %d, %d", gyro_x, gyro_y, gyro_z);
+
+ if (gyro_x == 0) {
+ gyro_x = gyro_adjust_x;
+ gyro_adjust_x *= -1;
+ }
+
+ if (gyro_y == 0) {
+ gyro_y = gyro_adjust_y;
+ gyro_adjust_y *= -1;
+ }
+
+ if (gyro_z == 0) {
+ gyro_z = gyro_adjust_z;
+ gyro_adjust_z *= -1;
+ }
input_report_rel(data->input_data, REL_RX, gyro_x);
input_report_rel(data->input_data, REL_RY, gyro_y);
{
int delay = 0;
int ret = 0;
- int enable = 0;
char sensor_data [__MAX_BUF_SENSOR];
- memset(sensor_data, 0, __MAX_BUF_SENSOR);
+ memset(sensor_data, 0, sizeof(sensor_data));
ret = get_sensor_data(sensor_type_gyro_delay, sensor_data);
if (ret) {
}
delay = sensor_atoi(sensor_data);
-
- ret = get_sensor_data(sensor_type_gyro_enable, sensor_data);
- if (ret) {
- ERR("failed to get initial enable");
- return ret;
- }
-
- enable = sensor_atoi(sensor_data);
-
if (delay < 0) {
ERR("weird value is set initial delay");
return ret;
atomic_set(&data->poll_delay, delay);
- if (enable) {
- atomic_set(&data->enable, 1);
- schedule_delayed_work(&data->work, 0);
- }
+ memset(sensor_data, 0, sizeof(sensor_data));
+ sensor_data[0] = '0';
+
+ set_sensor_data(sensor_type_gyro_enable, sensor_data);
+ atomic_set(&data->enable, 0);
return ret;
}
--- /dev/null
+/*
+ * Maru Virtio HRM(HeartBeat Rate Monitor) Sensor Device Driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Jinhyung Choi <jinhyung2.choi@samsung.com>
+ * Sangho Park <sangho1206.park@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "maru_virtio_sensor.h"
+
+struct maru_hrm_data {
+ struct input_dev *input_data;
+ struct delayed_work work;
+ struct mutex data_mutex;
+
+ struct virtio_sensor* vs;
+
+ atomic_t enable;
+ atomic_t poll_delay;
+};
+
+static struct device *hrm_sensor_device;
+
+static void maru_hrm_input_work_func(struct work_struct *work) {
+
+ int poll_time = 200000000;
+ int enable = 0;
+ int ret = 0;
+ int hrm = 0, rri = 0;
+ char sensor_data[__MAX_BUF_SENSOR];
+ struct maru_hrm_data *data = container_of((struct delayed_work *)work,
+ struct maru_hrm_data, work);
+
+ LOG(1, "maru_hrm_input_work_func starts");
+
+ memset(sensor_data, 0, __MAX_BUF_SENSOR);
+ poll_time = atomic_read(&data->poll_delay);
+
+ mutex_lock(&data->data_mutex);
+ enable = atomic_read(&data->enable);
+ mutex_unlock(&data->data_mutex);
+
+ if (enable) {
+ mutex_lock(&data->data_mutex);
+ ret = get_sensor_data(sensor_type_hrm, sensor_data);
+ mutex_unlock(&data->data_mutex);
+ if (!ret) {
+ sscanf(sensor_data, "%d, %d", &hrm, &rri);
+ LOG(1, "hrm_set %d %d", hrm, rri);
+
+ input_report_rel(data->input_data, REL_X, hrm + 1);
+ input_report_rel(data->input_data, REL_Y, rri + 1);
+ input_report_rel(data->input_data, REL_Z, 1);
+ input_sync(data->input_data);
+ }
+ }
+
+ mutex_lock(&data->data_mutex);
+ enable = atomic_read(&data->enable);
+ mutex_unlock(&data->data_mutex);
+
+ LOG(1, "enable: %d, poll_time: %d", enable, poll_time);
+ if (enable) {
+ if (poll_time > 0) {
+ schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time));
+ } else {
+ schedule_delayed_work(&data->work, 0);
+ }
+ }
+
+ LOG(1, "maru_hrm_input_work_func ends");
+
+}
+
+static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s", MARU_HRM_DEVICE_NAME);
+}
+
+static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR);
+}
+
+static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return get_data_for_show(sensor_type_hrm_enable, buf);
+}
+
+static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct input_dev *input_data = to_input_dev(dev);
+ struct maru_hrm_data *data = input_get_drvdata(input_data);
+ int value = simple_strtoul(buf, NULL, 10);
+
+ if (value != 0 && value != 1)
+ return count;
+
+ set_sensor_data(sensor_type_hrm_enable, buf);
+
+ if (value) {
+ if (atomic_read(&data->enable) != 1) {
+ atomic_set(&data->enable, 1);
+ schedule_delayed_work(&data->work, 0);
+
+ }
+ } else {
+ if (atomic_read(&data->enable) != 0) {
+ atomic_set(&data->enable, 0);
+ cancel_delayed_work(&data->work);
+ }
+ }
+
+ return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return get_data_for_show(sensor_type_hrm_delay, buf);
+}
+
+static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct input_dev *input_data = to_input_dev(dev);
+ struct maru_hrm_data *data = input_get_drvdata(input_data);
+ int value = simple_strtoul(buf, NULL, 10);
+
+ set_sensor_data(sensor_type_hrm_delay, buf);
+ atomic_set(&data->poll_delay, value);
+
+ return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_sensor_name =
+ __ATTR(name, S_IRUGO, maru_name_show, NULL);
+
+static struct device_attribute dev_attr_sensor_vendor =
+ __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL);
+
+static struct device_attribute *hrm_sensor_attrs [] = {
+ &dev_attr_sensor_name,
+ &dev_attr_sensor_vendor,
+ NULL,
+};
+
+static struct device_attribute attr_hrm [] =
+{
+ MARU_ATTR_RW(enable),
+ MARU_ATTR_RW(poll_delay),
+};
+
+static struct attribute *maru_hrm_attribute[] = {
+ &attr_hrm[0].attr,
+ &attr_hrm[1].attr,
+ NULL
+};
+
+static struct attribute_group maru_hrm_attribute_group = {
+ .attrs = maru_hrm_attribute
+};
+
+static void hrm_clear(struct maru_hrm_data *data) {
+ if (data == NULL)
+ return;
+
+ if (data->input_data) {
+ sysfs_remove_group(&data->input_data->dev.kobj,
+ &maru_hrm_attribute_group);
+ input_free_device(data->input_data);
+ }
+
+ kfree(data);
+ data = NULL;
+}
+
+static int set_initial_value(struct maru_hrm_data *data)
+{
+ int delay = 0;
+ int ret = 0;
+ int enable = 0;
+ char sensor_data [__MAX_BUF_SENSOR];
+
+ memset(sensor_data, 0, __MAX_BUF_SENSOR);
+
+ ret = get_sensor_data(sensor_type_hrm_delay, sensor_data);
+ if (ret) {
+ ERR("failed to get initial delay time");
+ return ret;
+ }
+
+ delay = sensor_atoi(sensor_data);
+
+ ret = get_sensor_data(sensor_type_hrm_enable, sensor_data);
+ if (ret) {
+ ERR("failed to get initial enable");
+ return ret;
+ }
+
+ enable = sensor_atoi(sensor_data);
+
+ if (delay < 0) {
+ ERR("weird value is set initial delay");
+ return ret;
+ }
+
+ atomic_set(&data->poll_delay, delay);
+
+ if (enable) {
+ atomic_set(&data->enable, 1);
+ schedule_delayed_work(&data->work, 0);
+ }
+
+ return ret;
+}
+
+static int create_input_device(struct maru_hrm_data *data)
+{
+ int ret = 0;
+ struct input_dev *input_data = NULL;
+
+ input_data = input_allocate_device();
+ if (input_data == NULL) {
+ ERR("failed initialing input handler");
+ hrm_clear(data);
+ return -ENOMEM;
+ }
+
+ input_data->name = SENSOR_HRM_INPUT_NAME;
+ input_data->id.bustype = BUS_I2C;
+
+ set_bit(EV_REL, input_data->evbit);
+ input_set_capability(input_data, EV_REL, REL_X);
+ input_set_capability(input_data, EV_REL, REL_Y);
+ input_set_capability(input_data, EV_REL, REL_Z);
+
+ data->input_data = input_data;
+
+ ret = input_register_device(input_data);
+ if (ret) {
+ ERR("failed to register input data");
+ hrm_clear(data);
+ return ret;
+ }
+
+ input_set_drvdata(input_data, data);
+
+ ret = sysfs_create_group(&input_data->dev.kobj,
+ &maru_hrm_attribute_group);
+ if (ret) {
+ hrm_clear(data);
+ ERR("failed initialing devices");
+ return ret;
+ }
+
+ return ret;
+}
+
+int maru_hrm_init(struct virtio_sensor *vs) {
+ int ret = 0;
+ struct maru_hrm_data *data = NULL;
+
+ INFO("maru_hrm device init starts.");
+
+ data = kmalloc(sizeof(struct maru_hrm_data), GFP_KERNEL);
+ if (data == NULL) {
+ ERR("failed to create hrm data.");
+ return -ENOMEM;
+ }
+
+ vs->hrm_handle = data;
+ data->vs = vs;
+
+ mutex_init(&data->data_mutex);
+
+ INIT_DELAYED_WORK(&data->work, maru_hrm_input_work_func);
+
+ // create name & vendor
+ ret = register_sensor_device(hrm_sensor_device, vs,
+ hrm_sensor_attrs, DRIVER_HRM_NAME);
+ if (ret) {
+ ERR("failed to register hrm device");
+ hrm_clear(data);
+ return -1;
+ }
+
+ // create input
+ ret = create_input_device(data);
+ if (ret) {
+ ERR("failed to create input device");
+ return ret;
+ }
+
+ // set initial delay & enable
+ ret = set_initial_value(data);
+ if (ret) {
+ ERR("failed to set initial value");
+ return ret;
+ }
+
+ INFO("maru_hrm device init ends.");
+
+ return ret;
+}
+
+int maru_hrm_exit(struct virtio_sensor *vs) {
+ struct maru_hrm_data *data = NULL;
+
+ data = (struct maru_hrm_data *)vs->hrm_handle;
+ hrm_clear(data);
+ INFO("maru_hrm device exit ends.");
+ return 0;
+}
sscanf(sensor_data, "%d", &light);
LOG(1, "light_set %d", light);
- input_report_rel(data->input_data, REL_RX, light); // LUX
- input_report_rel(data->input_data, REL_HWHEEL, 0); // red
- input_report_rel(data->input_data, REL_DIAL, 0); // green
- input_report_rel(data->input_data, REL_WHEEL, 0); // blue
- input_report_rel(data->input_data, REL_MISC, 0); // white
+ input_report_rel(data->input_data, REL_RX, (light + 1)); // LUX
+ input_report_rel(data->input_data, REL_HWHEEL, 0); // red
+ input_report_rel(data->input_data, REL_DIAL, 0); // green
+ input_report_rel(data->input_data, REL_WHEEL, 0); // blue
+ input_report_rel(data->input_data, REL_MISC, 0); // white
input_sync(data->input_data);
}
}
--- /dev/null
+/*
+ * Maru Virtio Pressure Sensor Device Driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Jinhyung Choi <jinhyung2.choi@samsung.com>
+ * Sangho Park <sangho1206.park@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "maru_virtio_sensor.h"
+
+struct maru_pressure_data {
+ struct input_dev *input_data;
+ struct delayed_work work;
+ struct mutex data_mutex;
+
+ struct virtio_sensor* vs;
+
+ atomic_t enable;
+ atomic_t poll_delay;
+};
+
+static struct device *pressure_sensor_device;
+
+#define PRESSURE_ADJUST 193
+static int pressure_convert_data(int number)
+{
+ return number * 10000 / PRESSURE_ADJUST;
+}
+
+#define TEMP_ADJUST 2
+static short temp_convert_data(int number)
+{
+ int temp;
+ temp = number * TEMP_ADJUST;
+ return (short)temp;
+}
+
+static void maru_pressure_input_work_func(struct work_struct *work) {
+
+ int poll_time = 200000000;
+ int enable = 0;
+ int ret = 0;
+ int pressure = 0;
+ int temperature = 0;
+ int raw_pressure;
+ short raw_temp;
+ char sensor_data[__MAX_BUF_SENSOR];
+ struct maru_pressure_data *data = container_of((struct delayed_work *)work,
+ struct maru_pressure_data, work);
+
+ LOG(1, "maru_pressure_input_work_func starts");
+
+ memset(sensor_data, 0, sizeof(sensor_data));
+ poll_time = atomic_read(&data->poll_delay);
+
+ mutex_lock(&data->data_mutex);
+ enable = atomic_read(&data->enable);
+ mutex_unlock(&data->data_mutex);
+
+ if (enable) {
+ mutex_lock(&data->data_mutex);
+ ret = get_sensor_data(sensor_type_pressure, sensor_data);
+ mutex_unlock(&data->data_mutex);
+ if (!ret) {
+ sscanf(sensor_data, "%d, %d", &pressure, &temperature);
+ LOG(1, "pressure_set %d, %d", pressure, temperature);
+
+ raw_pressure = pressure_convert_data(pressure);
+ if (temperature == 0) {
+ temperature = 1;
+ }
+ raw_temp = temp_convert_data(temperature);
+
+ LOG(1, "pressure raw pressure %d, temp %d.\n", raw_pressure, raw_temp);
+
+ input_report_rel(data->input_data, REL_HWHEEL, raw_pressure);
+ input_report_rel(data->input_data, REL_DIAL, 101325);
+ input_report_rel(data->input_data, REL_WHEEL, raw_temp);
+ input_sync(data->input_data);
+ }
+ }
+
+ mutex_lock(&data->data_mutex);
+ enable = atomic_read(&data->enable);
+ mutex_unlock(&data->data_mutex);
+
+ LOG(1, "enable: %d, poll_time: %d", enable, poll_time);
+ if (enable) {
+ if (poll_time > 0) {
+ schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time));
+ } else {
+ schedule_delayed_work(&data->work, 0);
+ }
+ }
+
+ LOG(1, "maru_pressure_input_work_func ends");
+
+}
+
+static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s", MARU_PRESSURE_DEVICE_NAME);
+}
+
+static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR);
+}
+
+static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return get_data_for_show(sensor_type_pressure_enable, buf);
+}
+
+static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct input_dev *input_data = to_input_dev(dev);
+ struct maru_pressure_data *data = input_get_drvdata(input_data);
+ int value = simple_strtoul(buf, NULL, 10);
+
+ if (value != 0 && value != 1)
+ return count;
+
+ set_sensor_data(sensor_type_pressure_enable, buf);
+
+ if (value) {
+ if (atomic_read(&data->enable) != 1) {
+ atomic_set(&data->enable, 1);
+ schedule_delayed_work(&data->work, 0);
+
+ }
+ } else {
+ if (atomic_read(&data->enable) != 0) {
+ atomic_set(&data->enable, 0);
+ cancel_delayed_work(&data->work);
+ }
+ }
+
+ return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return get_data_for_show(sensor_type_pressure_delay, buf);
+}
+
+static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct input_dev *input_data = to_input_dev(dev);
+ struct maru_pressure_data *data = input_get_drvdata(input_data);
+ int value = simple_strtoul(buf, NULL, 10);
+
+ set_sensor_data(sensor_type_pressure_delay, buf);
+ atomic_set(&data->poll_delay, value);
+
+ return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_sensor_name =
+ __ATTR(name, S_IRUGO, maru_name_show, NULL);
+
+static struct device_attribute dev_attr_sensor_vendor =
+ __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL);
+
+static struct device_attribute *pressure_sensor_attrs [] = {
+ &dev_attr_sensor_name,
+ &dev_attr_sensor_vendor,
+ NULL,
+};
+
+static struct device_attribute attr_pressure [] =
+{
+ MARU_ATTR_RW(enable),
+ MARU_ATTR_RW(poll_delay),
+};
+
+static struct attribute *maru_pressure_attribute[] = {
+ &attr_pressure[0].attr,
+ &attr_pressure[1].attr,
+ NULL
+};
+
+static struct attribute_group maru_pressure_attribute_group = {
+ .attrs = maru_pressure_attribute
+};
+
+static void pressure_clear(struct maru_pressure_data *data) {
+ if (data == NULL)
+ return;
+
+ if (data->input_data) {
+ sysfs_remove_group(&data->input_data->dev.kobj,
+ &maru_pressure_attribute_group);
+ input_free_device(data->input_data);
+ }
+
+ kfree(data);
+ data = NULL;
+}
+
+static int set_initial_value(struct maru_pressure_data *data)
+{
+ int delay = 0;
+ int ret = 0;
+ int enable = 0;
+ char sensor_data [__MAX_BUF_SENSOR];
+
+ memset(sensor_data, 0, sizeof(sensor_data));
+
+ ret = get_sensor_data(sensor_type_pressure_delay, sensor_data);
+ if (ret) {
+ ERR("failed to get initial delay time");
+ return ret;
+ }
+
+ delay = sensor_atoi(sensor_data);
+
+ ret = get_sensor_data(sensor_type_pressure_enable, sensor_data);
+ if (ret) {
+ ERR("failed to get initial enable");
+ return ret;
+ }
+
+ enable = sensor_atoi(sensor_data);
+
+ if (delay < 0) {
+ ERR("weird value is set initial delay");
+ return ret;
+ }
+
+ atomic_set(&data->poll_delay, delay);
+
+ if (enable) {
+ atomic_set(&data->enable, 1);
+ schedule_delayed_work(&data->work, 0);
+ }
+
+ return ret;
+}
+
+static int create_input_device(struct maru_pressure_data *data)
+{
+ int ret = 0;
+ struct input_dev *input_data = NULL;
+
+ input_data = input_allocate_device();
+ if (input_data == NULL) {
+ ERR("failed initialing input handler");
+ pressure_clear(data);
+ return -ENOMEM;
+ }
+
+ input_data->name = SENSOR_PRESSURE_INPUT_NAME;
+ input_data->id.bustype = BUS_I2C;
+
+ set_bit(EV_REL, input_data->evbit);
+ input_set_capability(input_data, EV_REL, REL_HWHEEL);
+ input_set_capability(input_data, EV_REL, REL_DIAL);
+ input_set_capability(input_data, EV_REL, REL_WHEEL);
+
+ data->input_data = input_data;
+
+ ret = input_register_device(input_data);
+ if (ret) {
+ ERR("failed to register input data");
+ pressure_clear(data);
+ return ret;
+ }
+
+ input_set_drvdata(input_data, data);
+
+ ret = sysfs_create_group(&input_data->dev.kobj,
+ &maru_pressure_attribute_group);
+ if (ret) {
+ pressure_clear(data);
+ ERR("failed initialing devices");
+ return ret;
+ }
+
+ return ret;
+}
+
+int maru_pressure_init(struct virtio_sensor *vs) {
+ int ret = 0;
+ struct maru_pressure_data *data = NULL;
+
+ INFO("maru_pressure device init starts.");
+
+ data = kmalloc(sizeof(struct maru_pressure_data), GFP_KERNEL);
+ if (data == NULL) {
+ ERR("failed to create pressure data.");
+ return -ENOMEM;
+ }
+
+ vs->pressure_handle = data;
+ data->vs = vs;
+
+ mutex_init(&data->data_mutex);
+
+ INIT_DELAYED_WORK(&data->work, maru_pressure_input_work_func);
+
+ // create name & vendor
+ ret = register_sensor_device(pressure_sensor_device, vs,
+ pressure_sensor_attrs, DRIVER_PRESSURE_NAME);
+ if (ret) {
+ ERR("failed to register pressure device");
+ pressure_clear(data);
+ return -1;
+ }
+
+ // create input
+ ret = create_input_device(data);
+ if (ret) {
+ ERR("failed to create input device");
+ return ret;
+ }
+
+ // set initial delay & enable
+ ret = set_initial_value(data);
+ if (ret) {
+ ERR("failed to set initial value");
+ return ret;
+ }
+
+ INFO("maru_pressure device init ends.");
+
+ return ret;
+}
+
+int maru_pressure_exit(struct virtio_sensor *vs) {
+ struct maru_pressure_data *data = NULL;
+
+ data = (struct maru_pressure_data *)vs->pressure_handle;
+ pressure_clear(data);
+ INFO("maru_pressure device exit ends.");
+ return 0;
+}
mutex_unlock(&data->data_mutex);
if (!ret) {
sscanf(sensor_data, "%d", &proxi);
- if (proxi)
+ if (!proxi)
proxi = 1;
+ else
+ proxi = 0;
+
LOG(1, "proxi_set %d", proxi);
- input_report_rel(data->input_data, ABS_DISTANCE, proxi);
+ input_report_abs(data->input_data, ABS_DISTANCE, proxi);
input_sync(data->input_data);
}
}
}
input_data->name = SENSOR_PROXI_INPUT_NAME;
- input_data->id.bustype = BUS_I2C;
+
+ input_set_drvdata(input_data, data);
set_bit(EV_ABS, input_data->evbit);
input_set_capability(input_data, EV_ABS, ABS_DISTANCE);
+ input_set_abs_params(input_data, ABS_DISTANCE, 0, 1, 0, 0);
data->input_data = input_data;
return ret;
}
- input_set_drvdata(input_data, data);
-
ret = sysfs_create_group(&input_data->dev.kobj,
&maru_proxi_attribute_group);
if (ret) {
--- /dev/null
+/*
+ * Maru Virtio UltraViolet Sensor Device Driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Jinhyung Choi <jinhyung2.choi@samsung.com>
+ * Sangho Park <sangho1206.park@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "maru_virtio_sensor.h"
+
+struct maru_uv_data {
+ struct input_dev *input_data;
+ struct delayed_work work;
+ struct mutex data_mutex;
+
+ struct virtio_sensor* vs;
+
+ atomic_t enable;
+ atomic_t poll_delay;
+};
+
+static struct device *uv_sensor_device;
+
+static void maru_uv_input_work_func(struct work_struct *work) {
+
+ int poll_time = 200000000;
+ int enable = 0;
+ int ret = 0;
+ int uv = 0;
+ char sensor_data[__MAX_BUF_SENSOR];
+ struct maru_uv_data *data = container_of((struct delayed_work *)work,
+ struct maru_uv_data, work);
+
+ LOG(1, "maru_uv_input_work_func starts");
+
+ memset(sensor_data, 0, __MAX_BUF_SENSOR);
+ poll_time = atomic_read(&data->poll_delay);
+
+ mutex_lock(&data->data_mutex);
+ enable = atomic_read(&data->enable);
+ mutex_unlock(&data->data_mutex);
+
+ if (enable) {
+ mutex_lock(&data->data_mutex);
+ ret = get_sensor_data(sensor_type_uv, sensor_data);
+ mutex_unlock(&data->data_mutex);
+ if (!ret) {
+ sscanf(sensor_data, "%d", &uv);
+ LOG(1, "uv_set %d", uv);
+
+ input_report_rel(data->input_data, REL_MISC, (uv + 1));
+ input_sync(data->input_data);
+ }
+ }
+
+ mutex_lock(&data->data_mutex);
+ enable = atomic_read(&data->enable);
+ mutex_unlock(&data->data_mutex);
+
+ LOG(1, "enable: %d, poll_time: %d", enable, poll_time);
+ if (enable) {
+ if (poll_time > 0) {
+ schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time));
+ } else {
+ schedule_delayed_work(&data->work, 0);
+ }
+ }
+
+ LOG(1, "maru_uv_input_work_func ends");
+
+}
+
+static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s", MARU_UV_DEVICE_NAME);
+}
+
+static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR);
+}
+
+static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return get_data_for_show(sensor_type_uv_enable, buf);
+}
+
+static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct input_dev *input_data = to_input_dev(dev);
+ struct maru_uv_data *data = input_get_drvdata(input_data);
+ int value = simple_strtoul(buf, NULL, 10);
+
+ if (value != 0 && value != 1)
+ return count;
+
+ set_sensor_data(sensor_type_uv_enable, buf);
+
+ if (value) {
+ if (atomic_read(&data->enable) != 1) {
+ atomic_set(&data->enable, 1);
+ schedule_delayed_work(&data->work, 0);
+
+ }
+ } else {
+ if (atomic_read(&data->enable) != 0) {
+ atomic_set(&data->enable, 0);
+ cancel_delayed_work(&data->work);
+ }
+ }
+
+ return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return get_data_for_show(sensor_type_uv_delay, buf);
+}
+
+static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct input_dev *input_data = to_input_dev(dev);
+ struct maru_uv_data *data = input_get_drvdata(input_data);
+ int value = simple_strtoul(buf, NULL, 10);
+
+ set_sensor_data(sensor_type_uv_delay, buf);
+ atomic_set(&data->poll_delay, value);
+
+ return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_sensor_name =
+ __ATTR(name, S_IRUGO, maru_name_show, NULL);
+
+static struct device_attribute dev_attr_sensor_vendor =
+ __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL);
+
+static struct device_attribute *uv_sensor_attrs [] = {
+ &dev_attr_sensor_name,
+ &dev_attr_sensor_vendor,
+ NULL,
+};
+
+static struct device_attribute attr_uv [] =
+{
+ MARU_ATTR_RW(enable),
+ MARU_ATTR_RW(poll_delay),
+};
+
+static struct attribute *maru_uv_attribute[] = {
+ &attr_uv[0].attr,
+ &attr_uv[1].attr,
+ NULL
+};
+
+static struct attribute_group maru_uv_attribute_group = {
+ .attrs = maru_uv_attribute
+};
+
+static void uv_clear(struct maru_uv_data *data) {
+ if (data == NULL)
+ return;
+
+ if (data->input_data) {
+ sysfs_remove_group(&data->input_data->dev.kobj,
+ &maru_uv_attribute_group);
+ input_free_device(data->input_data);
+ }
+
+ kfree(data);
+ data = NULL;
+}
+
+static int set_initial_value(struct maru_uv_data *data)
+{
+ int delay = 0;
+ int ret = 0;
+ int enable = 0;
+ char sensor_data [__MAX_BUF_SENSOR];
+
+ memset(sensor_data, 0, __MAX_BUF_SENSOR);
+
+ ret = get_sensor_data(sensor_type_uv_delay, sensor_data);
+ if (ret) {
+ ERR("failed to get initial delay time");
+ return ret;
+ }
+
+ delay = sensor_atoi(sensor_data);
+
+ ret = get_sensor_data(sensor_type_uv_enable, sensor_data);
+ if (ret) {
+ ERR("failed to get initial enable");
+ return ret;
+ }
+
+ enable = sensor_atoi(sensor_data);
+
+ if (delay < 0) {
+ ERR("weird value is set initial delay");
+ return ret;
+ }
+
+ atomic_set(&data->poll_delay, delay);
+
+ if (enable) {
+ atomic_set(&data->enable, 1);
+ schedule_delayed_work(&data->work, 0);
+ }
+
+ return ret;
+}
+
+static int create_input_device(struct maru_uv_data *data)
+{
+ int ret = 0;
+ struct input_dev *input_data = NULL;
+
+ input_data = input_allocate_device();
+ if (input_data == NULL) {
+ ERR("failed initialing input handler");
+ uv_clear(data);
+ return -ENOMEM;
+ }
+
+ input_data->name = SENSOR_UV_INPUT_NAME;
+ input_data->id.bustype = BUS_I2C;
+
+ set_bit(EV_REL, input_data->evbit);
+ input_set_capability(input_data, EV_REL, REL_MISC);
+
+ data->input_data = input_data;
+
+ ret = input_register_device(input_data);
+ if (ret) {
+ ERR("failed to register input data");
+ uv_clear(data);
+ return ret;
+ }
+
+ input_set_drvdata(input_data, data);
+
+ ret = sysfs_create_group(&input_data->dev.kobj,
+ &maru_uv_attribute_group);
+ if (ret) {
+ uv_clear(data);
+ ERR("failed initialing devices");
+ return ret;
+ }
+
+ return ret;
+}
+
+int maru_uv_init(struct virtio_sensor *vs) {
+ int ret = 0;
+ struct maru_uv_data *data = NULL;
+
+ INFO("maru_uv device init starts.");
+
+ data = kmalloc(sizeof(struct maru_uv_data), GFP_KERNEL);
+ if (data == NULL) {
+ ERR("failed to create uv data.");
+ return -ENOMEM;
+ }
+
+ vs->uv_handle = data;
+ data->vs = vs;
+
+ mutex_init(&data->data_mutex);
+
+ INIT_DELAYED_WORK(&data->work, maru_uv_input_work_func);
+
+ // create name & vendor
+ ret = register_sensor_device(uv_sensor_device, vs,
+ uv_sensor_attrs, DRIVER_UV_NAME);
+ if (ret) {
+ ERR("failed to register uv device");
+ uv_clear(data);
+ return -1;
+ }
+
+ // create input
+ ret = create_input_device(data);
+ if (ret) {
+ ERR("failed to create input device");
+ return ret;
+ }
+
+ // set initial delay & enable
+ ret = set_initial_value(data);
+ if (ret) {
+ ERR("failed to set initial value");
+ return ret;
+ }
+
+ INFO("maru_uv device init ends.");
+
+ return ret;
+}
+
+int maru_uv_exit(struct virtio_sensor *vs) {
+ struct maru_uv_data *data = NULL;
+
+ data = (struct maru_uv_data *)vs->uv_handle;
+ uv_clear(data);
+ INFO("maru_uv device exit ends.");
+ return 0;
+}
ERR("failed to init haptic with error %d", ret);
}
}
+
+ if (vs->sensor_capability & sensor_cap_pressure) {
+ ret = maru_pressure_init(vs);
+ if (ret) {
+ vs->sensor_fail_init |= sensor_cap_pressure;
+ ERR("failed to init pressure with error %d", ret);
+ }
+ }
+
+ if (vs->sensor_capability & sensor_cap_uv) {
+ ret = maru_uv_init(vs);
+ if (ret) {
+ vs->sensor_fail_init |= sensor_cap_uv;
+ ERR("failed to init uv with error %d", ret);
+ }
+ }
+
+ if (vs->sensor_capability & sensor_cap_hrm) {
+ ret = maru_hrm_init(vs);
+ if (ret) {
+ vs->sensor_fail_init |= sensor_cap_hrm;
+ ERR("failed to init hrm with error %d", ret);
+ }
+ }
}
static void device_exit(struct virtio_sensor *vs)
!(vs->sensor_fail_init & sensor_cap_haptic)) {
maru_haptic_exit(vs);
}
+
+ if (vs->sensor_capability & sensor_cap_pressure &&
+ !(vs->sensor_fail_init & sensor_cap_pressure)) {
+ maru_pressure_exit(vs);
+ }
+
+ if (vs->sensor_capability & sensor_cap_uv &&
+ !(vs->sensor_fail_init & sensor_cap_uv)) {
+ maru_uv_exit(vs);
+ }
+
+ if (vs->sensor_capability & sensor_cap_hrm &&
+ !(vs->sensor_fail_init & sensor_cap_hrm)) {
+ maru_hrm_exit(vs);
+ }
}
static void cleanup(struct virtio_device* dev) {
sensor_type_rotation_vector_delay,
sensor_type_mag,
sensor_type_tilt,
+ sensor_type_pressure,
+ sensor_type_pressure_enable,
+ sensor_type_pressure_delay,
+ sensor_type_uv,
+ sensor_type_uv_enable,
+ sensor_type_uv_delay,
+ sensor_type_hrm,
+ sensor_type_hrm_heart,
+ sensor_type_hrm_rri,
+ sensor_type_hrm_enable,
+ sensor_type_hrm_delay,
sensor_type_max
};
enum sensor_capabilities {
- sensor_cap_accel = 0x01,
- sensor_cap_geo = 0x02,
- sensor_cap_gyro = 0x04,
- sensor_cap_light = 0x08,
- sensor_cap_proxi = 0x10,
- sensor_cap_rotation_vector = 0x20,
- sensor_cap_haptic = 0x40
+ sensor_cap_accel = 0x0001,
+ sensor_cap_geo = 0x0002,
+ sensor_cap_gyro = 0x0004,
+ sensor_cap_light = 0x0008,
+ sensor_cap_proxi = 0x0010,
+ sensor_cap_rotation_vector = 0x0020,
+ sensor_cap_haptic = 0x0040,
+ sensor_cap_pressure = 0x0080,
+ sensor_cap_uv = 0x0100,
+ sensor_cap_hrm = 0x0200
};
#define __MAX_BUF_SIZE 1024
void* proxi_handle;
void* rotation_vector_handle;
void* haptic_handle;
+ void* pressure_handle;
+ void* uv_handle;
+ void* hrm_handle;
};
#define MARU_DEVICE_ATTR(_name) \
#define SENSOR_HAPTIC_INPUT_NAME "haptic_sensor"
+#define DRIVER_PRESSURE_NAME "pressure"
+#define SENSOR_PRESSURE_INPUT_NAME "pressure_sensor"
+#define MARU_PRESSURE_DEVICE_NAME "maru_sensor_pressure_1"
+
+#define DRIVER_UV_NAME "ultraviolet"
+#define SENSOR_UV_INPUT_NAME "uv_sensor"
+#define MARU_UV_DEVICE_NAME "maru_sensor_uv_1"
+
+#define DRIVER_HRM_NAME "hrm"
+#define SENSOR_HRM_INPUT_NAME "hrm_lib_sensor"
+#define MARU_HRM_DEVICE_NAME "maru_sensor_hrm_1"
+
// It locates /sys/module/maru_virtio_sensor/parameters/sensor_driver_debug
extern int sensor_driver_debug;
int maru_haptic_init(struct virtio_sensor *vs);
int maru_haptic_exit(struct virtio_sensor *vs);
+/*
+ * Pressure device
+ */
+int maru_pressure_init(struct virtio_sensor *vs);
+int maru_pressure_exit(struct virtio_sensor *vs);
+
+/*
+ * UV(UltraViolet) device
+ */
+int maru_uv_init(struct virtio_sensor *vs);
+int maru_uv_exit(struct virtio_sensor *vs);
+
+/*
+ * HRM(Heart Beat Rate) device
+ */
+int maru_hrm_init(struct virtio_sensor *vs);
+int maru_hrm_exit(struct virtio_sensor *vs);
+
#endif